调用匿名类的方法

时间:2015-10-05 23:54:34

标签: java class

我前几天才知道你可以做到这一点

new Object() {
    void hello() {
        System.out.println("Hello World!");
    }
}.hello();

这对我来说似乎很奇怪。当然,创建的对象的静态类型是Object,所以没有方法hello()?它几乎完全没有意义(例如,不可能两次调用hello。)

我有2个问题。

  1. 有人能指出我解决此问题的规范部分吗?
  2. 我是否正确地认为你可以调用hello的唯一方法就是这样。反思怎么样?
  3. 由于

4 个答案:

答案 0 :(得分:16)

  

有人能指出我解决这个问题的规范部分吗?

这主要在关于Method invocation expressions

的部分中定义
  

在编译时处理方法调用的第一步是   弄清楚要调用的方法的名称以及哪个类或   用于搜索该名称方法定义的界面。

     

对于要搜索的类或接口,有六种情况需要考虑,   取决于在左括号之前的形式   的MethodInvocation:

     
      
  • [...]
  •   
  • 如果表单为Primary . [TypeArguments] Identifier,请让T成为。{1}}   主表达式的类型。要搜索的类或接口   如果T是类或接口类型,则为T;如果为T,则为T的上限   是一个类型变量。
  •   

此处,主要表达式class instance creation expression。所以要搜索的类型是匿名类型。

  

我认为你可以调用你好的唯一方法是对的   就像这样。反思怎么样?

只要表达式评估为匿名类型T,无论是通过直接访问还是通过泛型,您都可以访问{常规访问规则适用于T声明的成员。这不仅限于方法。您可以访问字段或类型,但它对类型没有用。例如,

Object var = new Object() {
    class Nested {
    }
}.new Nested();

由于无法在没有封闭类型的情况下引用嵌套类型,因此无法声明该嵌套类型的变量。实用性很快下降。 (据推测,这也是为什么你不能在这个匿名类中使用static嵌套类型。)

反射也暴露了这种方法。生成的匿名类包含此方法,因此您可以检索它并调用它。过程是一样的。实例来自匿名类的事实并不重要。适用How do I invoke a Java method when given the method name as a string?中提出的相同策略。

例如,

Object ref = new Object() {
    public void method() {
        System.out.println("hidden");
    }
};
Class<?> anonymousClass = ref.getClass();
Method method = anonymousClass.getMethod("method");
method.invoke(ref, new Object[0]);

不要写这样的代码。

答案 1 :(得分:12)

发布后,没有办法从Object实例获取匿名方法。并且,它使Anonymous classes看起来毫无意义。但是,您可以(我通常会)使用它来实现接口。像,

static interface Hello {
    void hello();
}
public static void main(String[] args) {
    Hello o = new Hello() {
        public void hello() {
            System.out.println("Hello World!");
        }
    };
    o.hello();
}

或者更常见的是,使用JFC / Swing和ActionListener进行回调。

答案 2 :(得分:11)

添加到Sotirios' answer,这里的 如何通过反射调用该方法:

setNeedsDisplay()

这允许你不止一次调用该方法,但除此之外,没有多大意义。

答案 3 :(得分:9)

匿名类是为了懒惰程序员的利益 - 命名事情太难了:)

匿名类非常像本地类。如果一个本地类只是用于创建一个对象,然后只用作超类型,我们可以创建一个更简洁的匿名类。

匿名类是不可否认的(程序员),这很好,因为我们不需要再次引用它。但是,对于编译器而言,该类的名称非常多,并且没有理由将它与显式命名的类区别对待。表达式的静态类型是具体的子类,对象的成员是该类的成员。此功能(能够呼叫hello())是否毫无意义?只有当你认为本地课程毫无意义时(实际上很少使用本地课程)。这是example,我使用了这个功能(为了好玩)。

虽然类型是不可否认的,但类型可以通过API自行存活。例如,

    Objects.requireNonNull( new Object(){ void hello(){} } ).hello();

即使我们无法命名该类型,也不需要将其命名为可推断的位置。

    Collections.singleton( new Object(){ void hello(){} } )
      .forEach( o->{ o.hello(); o.hello(); } );

我们可以为那些没有预料到静态类型

的人制作益智游戏
    Collections.singleton( new Object(){} ).add( new Object() ); // does not compile! why?