【问题标题】:Accessing constructor of an anonymous class访问匿名类的构造函数
【发布时间】:2010-09-26 14:52:50
【问题描述】:

假设我有一个具体的类 Class1,我正在用它创建一个匿名类。

Object a = new Class1(){
        void someNewMethod(){
        }
      };

现在有什么方法可以重载这个匿名类的构造函数。如下图所示

Object a = new Class1(){
        void someNewMethod(){
        }
        public XXXXXXXX(int a){
          super();
          System.out.println(a);
        }
      };

用 xxxxxxxx 处的东西来命名构造函数?

【问题讨论】:

标签: java constructor overloading anonymous-types


【解决方案1】:

来自Java Language Specification,第 15.9.5.1 节:

匿名类不能有 显式声明的构造函数。

对不起:(

编辑:作为替代方案,您可以创建一些最终局部变量,和/或在匿名类中包含实例初始化程序。例如:

public class Test {
    public static void main(String[] args) throws Exception {
        final int fakeConstructorArg = 10;

        Object a = new Object() {
            {
                System.out.println("arg = " + fakeConstructorArg);
            }
        };
    }
}

这很糟糕,但它可能会对你有所帮助。或者,使用适当的嵌套类:)

【讨论】:

  • Arne,我相信他没有抄袭。我认为他对 java 的了解足够多,足以公平地给予赞扬。
  • 天哪,有人指责乔恩·斯基特抄袭了吗?
  • 当该方法被覆盖时,我如何能够从 println 中调用 Test 超类中的方法?
  • @Zom-B:不清楚你的意思是什么——我怀疑你值得提出一个新问题,举一个你想要达到的目标。
  • 啊,我想覆盖超类构造函数...然后我明白no explicitly declared ctor 也意味着没有任何覆盖。我想。
【解决方案2】:

这是不可能的,但你可以像这样添加一个匿名初始化器:

final int anInt = ...;
Object a = new Class1()
{
  {
    System.out.println(anInt);
  }

  void someNewMethod() {
  }
};

不要忘记对匿名类使用的局部变量或参数的最终声明,就像我对 anInt 所做的那样。

【讨论】:

  • 其实很像构造函数。我可以访问抽象基类的受保护成员。在实例化匿名类之前,其他一切都可以在代码中完成。
【解决方案3】:

这是解决问题的另一种方法:

public class Test{

    public static final void main(String...args){

        new Thread(){

            private String message = null;

            Thread initialise(String message){

                this.message = message;
                return this;
            }

            public void run(){
                System.out.println(message);
            }
        }.initialise(args[0]).start();
    }
}

【讨论】:

  • 不错的解决方案,但这里使用 Thread 起初让人有些误解(有一刻我以为你创建了一个单独的线程来初始化东西!)
  • 请注意,在定义t 之后,您不能调用t.initialise(),除非在类/接口类型中定义了此函数。
  • @AramKocharyan 这使它更像一个构造函数。
  • 我喜欢这个解决方案!很明显,initialise() 方法是在 Thread 构造函数之后调用的。另一方面,(至少对我而言)并不明显的是,使用实例初始化程序总是可以保证这一点。
【解决方案4】:

我知道帖子太旧了,无法发布答案。不过我觉得还是值得的。

虽然你不能有一个显式的构造函数,但如果你的意图是调用超类的一个可能受保护的构造函数,那么你所要做的就是以下。

StoredProcedure sp = new StoredProcedure(datasource, spName) {
    {// init code if there are any}
};

这是在 Spring 中通过传递 DataSourceString 对象来创建 StoredProcedure 对象的示例。

所以底线是,如果你想创建一个匿名类并想调用超类构造函数,那么创建匿名类的签名匹配超类构造函数

【讨论】:

    【解决方案5】:

    是的,你不能在匿名类中定义构造是对的,但这并不意味着匿名类没有构造函数。迷惑... 实际上,您不能在 Anonymous 类中定义构造,但编译器会为它生成一个构造函数,其签名与其调用的父构造函数相同。如果 parent 有多个构造函数,则匿名将只有一个构造函数

    【讨论】:

      【解决方案6】:

      您可以在接受初始化参数的抽象类中拥有一个构造函数。 Java 规范只规定匿名类,它是(可选的)抽象类或接口实现的后代,不能拥有自己的构造函数。

      以下是绝对合法且可行的:

      static abstract class Q{
          int z;
          Q(int z){ this.z=z;}
          void h(){
              Q me = new Q(1) {
              };
          }
      }
      

      如果您有可能自己编写抽象类,请将这样的构造函数放在那里,并在没有更好解决方案的地方使用流畅的 API。您可以通过这种方式覆盖原始类的构造函数,使用带参数的构造函数创建一个命名的兄弟类,并使用它来实例化您的匿名类。

      【讨论】:

      • (匿名类的存在理由)如何在函数中包含该代码?
      【解决方案7】:

      如果你不需要传递参数,那么初始化代码就足够了,但是如果你需要从一个contrcutor传递参数,有一种方法可以解决大多数情况:

      Boolean var= new anonymousClass(){
          private String myVar; //String for example
      
          @Overriden public Boolean method(int i){
                //use myVar and i
          }
          public String setVar(String var){myVar=var; return this;} //Returns self instane
      }.setVar("Hello").method(3);
      

      【讨论】:

      • 如果我理解你的代码 anonymousClass 应该从 String 继承(setVar 是 String 的类型并返回这个),但 String 是不可扩展的。我猜 setVar 应该返回anonymousClass 扩展的内容。
      【解决方案8】:

      Peter Norvig 的 Java IAQ:不常回答的问题

      http://norvig.com/java-iaq.html#constructors - 匿名类构造器

      http://norvig.com/java-iaq.html#init - 构造函数和初始化

      求和,你可以构造这样的东西..

      public class ResultsBuilder {
          Set<Result> errors;
          Set<Result> warnings;
      
      ...
      
          public Results<E> build() {
              return new Results<E>() {
                  private Result[] errorsView;
                  private Result[] warningsView;
                  {
                      errorsView = ResultsBuilder.this.getErrors();
                      warningsView = ResultsBuilder.this.getWarnings();
                  }
      
                  public Result[] getErrors() {
                      return errorsView;
                  }
      
                  public Result[] getWarnings() {
                      return warningsView;
                  }
              };
          }
      
          public Result[] getErrors() {
              return !isEmpty(this.errors) ? errors.toArray(new Result[0]) : null;
          }
      
          public Result[] getWarnings() {
              return !isEmpty(this.warnings) ? warnings.toArray(new Result[0]) : null;
          }
      }
      

      【讨论】:

      • 我不认识Google的Scientific Peter Norvig,这可能是他早期的工作之一,是关于java 1.1的!从历史的角度来看很有趣:)
      【解决方案9】:

      在匿名类中使用命名的重载构造函数没有任何意义,因为无论如何都无法调用它。

      根据您实际尝试执行的操作,仅访问在类外部声明的最终局部变量,或使用 Arne 所示的实例初始化程序,可能是最佳解决方案。

      【讨论】:

      • 如果需要,该语言可以轻松地将“普通”构造函数参数转换为匿名类的参数。不过,构造函数声明的语法可能看起来很奇怪......
      • 不能像声明基类构造函数一样声明构造函数吗?我看不出有什么问题
      【解决方案10】:

      在我的例子中,本地类(带有自定义构造函数)作为匿名类工作:

      Object a = getClass1(x);
      
      public Class1 getClass1(int x) {
        class Class2 implements Class1 {
          void someNewMethod(){
          }
          public Class2(int a){
            super();
            System.out.println(a);
          }
        }
        Class1 c = new Class2(x);
        return c;
      }
      

      【讨论】:

        猜你喜欢
        • 2021-12-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多