调用一个匿名类的方法

我有一天学到了,你可以做到这一点

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

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

我有两个关于这个问题。

  1. 有人可以指点我的规范,这个地址呢?
  2. 我是否认为你能调用hello的唯一方法就是这样。 反思呢?

谢谢

有人可以指点我的规范,这个地址呢?

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

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

对于要search的类或接口,有六种情况需要考虑,具体取决于MethodInvocation左括号之前的forms:

  • […]
  • 如果表单是Primary . [TypeArguments] Identifier Primary . [TypeArguments] Identifier ,那么让T是主expression式的types。 如果T是一个类或接口types,则search的类或接口是T ,如果T是一个typesvariables,则T的上界是T

这里, 主expression式是类实例创buildexpression式 。 所以要search的types是匿名types。

我是否认为你能调用hello的唯一方法就是这样。 反思呢?

只要expression式的计算结果为匿名typesT ,无论是通过直接访问还是通过generics,您都可以访问(定期访问规则)给T声明的成员。 这不仅限于方法。 您可以访问字段或types,但对于types不是很有用。 例如,

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

由于无法引用嵌套types,因此无法声明嵌套types的variables。 有用性下降得非常快。 (据推测,这也是为什么你不能在这个匿名类中有一个static嵌套types。)

reflection也暴露了这种方法。 生成的匿名类包含这个方法,所以你可以检索它并调用它。 过程是一样的。 实例来自匿名类的事实并不重要。 在给出方法名称作为string时 , 如何调用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进行callback 。

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

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

这可以让你不止一次地调用这个方法,但除此之外,没有什么意义。

匿名类是为懒惰的程序员的利益 – 命名的东西太难了:)

匿名类非常像本地类。 如果一个本地类只是创build一个对象,而后者只能用作超types,我们可以创build一个更简洁的匿名类。

匿名类对程序员来说是不可否认的,这很好,因为我们不需要再次引用它。 然而,对于编译器来说,这个类是非常有名的,没有理由把它与明确命名的类区分开来。 expression式的静态types是具体的子类,而对象的成员是该类的成员。 这个function(能够打电话给hello() )没有意义吗? 只有当你认为当地的class级毫无意义(实际上本地class级很less使用)。 这里有一个例子 ,我用这个function(为了好玩)。

虽然types是不可否认的,但是types可以通过API来存活。 例如,

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

即使我们不能指定types,也不需要在可以推断的地方命名。

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

而且我们可以为那些不期待静态types的人创build一个迷惑者

  Collections.singleton( new Object(){} ).add( new Object() ); // does not compile! why?