调用一个匿名类的方法
我有一天学到了,你可以做到这一点
new Object() { void hello() { System.out.println("Hello World!"); } }.hello();
这对我来说似乎很奇怪。 当然,创build的Object
的静态types是Object
,所以没有方法hello()
? 是不是几乎完全没有意义(例如,不能调用hello
两次)。
我有两个关于这个问题。
- 有人可以指点我的规范,这个地址呢?
- 我是否认为你能调用
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?