可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Is there any Java syntax to access new methods defined within anonymous inner classes from outer class? I know there can be various workarounds, but I wonder if a special syntax exist?
For example
class Outer {
ActionListener listener = new ActionListener() {
@Override
void actionPerformed(ActionEvent e) {
// do something
}
// method is public so can be accessible
public void MyGloriousMethod() {
// viva!
}
};
public void Caller() {
listener.MyGloriousMethod(); // does not work!
}
}
MY OWN SOLUTION
I just moved all methods and members up to outer class.
回答1:
Once the anonymous class instance has been implicitly cast into the named type it can't be cast back because there is no name for the anonymous type. You can access the additional members of the anonymous inner class through this
within the class, in the expression immediate after the expression and the type can be inferred and returned through a method call.
Object obj = new Object() {
void fn() {
System.err.println("fn");
}
@Override public String toString() {
fn();
return "";
}
};
obj.toString();
new Object() {
void fn() {
System.err.println("fn");
}
}.fn();
identity(new Object() {
void fn() {
System.err.println("fn");
}
}).fn();
...
private static <T> T identity(T value) {
return value;
}
回答2:
A student in my class asked our professor if this could be done the other day. Here is what I wrote as a cool proof of concept that it CAN be done, although not worth it, it is actually possible and here is how:
public static void main(String[] args){
//anonymous inner class with method defined inside which
//does not override anything
Object o = new Object()
{
public int test = 5;
public void sayHello()
{
System.out.println("Hello World");
}
};
//o.sayHello();//Does not work
try
{
Method m = o.getClass().getMethod("sayHello");
Field f = o.getClass().getField("test");
System.out.println(f.getInt(o));
m.invoke(o);
} catch (Exception e)
{
e.printStackTrace();
}
}
By making use of Java's Method class we can invoke a method by passing in the string value and parameters of the method. Same thing can be done with fields.
Just thought it would be cool to share this!
回答3:
Your caller knows listener
as an ActionListener
and therefore it doesn't know anything about that new method. I think the only way to do this (other than doing reflection gymnastics, which really would defeat the purpose of using an anonymous class, i.e. shortcut/simplicity) is to simply subclass ActionListener
and not use an anonymous class.
回答4:
No, it's imposible. You would need to cast the ActionListener to its real subclass name, but since it's anonymous, it doesn't have a name.
回答5:
The right way to do it is using reflection:
import java.lang.reflect.InvocationTargetException;
public class MethodByReflectionTest {
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Object obj = new Object(){
public void print(){
System.out.println("Print executed.");
}
};
obj.getClass().getMethod("print", null).invoke(obj, null);
}
}
You can check here: How do I invoke a Java method when given the method name as a string?
回答6:
Funny enough, this is now allowed with var
construct (Java 10 or newer). Example:
var calculator = new Object() {
BigDecimal intermediateSum = BigDecimal.ZERO;
void calculate(Item item) {
intermediateSum = Numbers.add(intermediateSum, item.value);
item.sum= intermediateSum;
}
};
items.forEach(calculator::calculate);
Here with method reference, but works with dot method call as well, of course. It works with fields as well. Enjoy new Java. :-)
I found more tricks with var
and anonymous classes here: https://blog.codefx.org/java/tricks-var-anonymous-classes/
回答7:
Yes you can access the method see the example below if any doubt please comment
package com;
interface A
{
public void display();
}
public class Outer {
public static void main(String []args)
{
A a=new A() {
@Override
public void display() {
System.out.println("Hello");
}
};
a.display();
}
}