繁体   English   中英

调用匿名类的方法

[英]Invoking a method of an anonymous class

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

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

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

我有2个问题。

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

谢谢

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

这将主要在有关方法调用表达式的部分中定义:

在编译时处理方法调用的第一步是确定要调用的方法的名称以及要搜索该名称的方法定义的类或接口。

对于要搜索的类或接口,有六种情况需要考虑,具体取决于MethodInvocation左括号前面的表单:

  • [...]
  • 如果表单是Primary . [TypeArguments] Identifier Primary . [TypeArguments] Identifier ,然后让T为Primary表达式的类型。 如果T是类或接口类型,则搜索的类或接口是T ,如果T是类型变量,则是T的上限。

这里, Primary表达式类实例创建表达式 所以要搜索的类型是匿名类型。

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

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

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

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

反射也暴露了这种方法。 生成的匿名类包含此方法,因此您可以检索它并调用它。 过程是一样的。 实例来自匿名类的事实并不重要。 当将方法名称作为字符串时如何调用Java方法中提供的策略相同 适用。

例如,

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]);

不要写这样的代码。

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

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进行回调

添加到Sotirios的答案 ,这里是如何通过反射调用方法:

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

Method hello = o.getClass().getDeclaredMethod("hello");
hello.invoke(o);

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

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

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

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

虽然类型是不可否认的,但类型可以通过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?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM