Java反射获取匿名类';原点接口

Java反射获取匿名类';原点接口,java,swing,reflection,Java,Swing,Reflection,我有下面的HashMap。它的目的是用来调用扩展JPanel的类的某些方法。方法是HashMap中的值,传递的参数是键 HashMap<Object, String> methodMapper = new HashMap<>(); projectMethodMapper.put("Some title", "setInfoTitle"); projectMethodMapper.put(new ActionListener() { @Override

我有下面的HashMap。它的目的是用来调用扩展JPanel的类的某些方法。方法是HashMap中的值,传递的参数是键

HashMap<Object, String> methodMapper = new HashMap<>();

projectMethodMapper.put("Some title", "setInfoTitle");

projectMethodMapper.put(new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("working");
    }
}, "attachListener");
稍后,我遍历HashMap的键

InfoPanel infoPanel = new InfoPanel();

for (Object key : keys) {
    Method method = InfoPanel.class.getDeclaredMethod(methodMapper.get(key), key.getClass());

    method.invoke(infoPanel, key));
}

可以想象,当键是字符串对象时没有问题,当getDeclaredMethod搜索参数类型为MainPanel$1 As的方法attachListener时就会出现问题。getClass返回MainPanel$1,因为它是动态创建的匿名类。我的问题是-如何找到用于创建用于对象实例化的匿名类的接口?

您不需要为此使用反射。您可以使用
列表
,它主要是一个函数列表,每个函数都以
InfoPanel
作为参数:

List<Consumer<InfoPanel>> commandList = new ArrayList<>();

commandList.add(panel -> 
    panel.attachListener(e -> System.out.println("working")) // using lambda for brievety
);

commandList.add(panel -> panel.setInfoTitle("Some Title"));
当然,这利用了Java8,但是如果需要,Java7也可以这样做


如果坚持使用反射,则可以创建一个数据类型来存储预期的参数类型以及方法名称和参数:

class Signature {
    private final String name;
    private final Class<?>[] parameters;
    private final Object[] arguments;

    ...
}

对你的问题的简单回答

如何找到用于创建用于对象实例化的匿名类的接口

在下面的代码段中。但是请注意,您的方法可能会有很大的问题,如果可能的话,您可能应该尝试重构它

public class Main {
    private static Class<?> getDeclaredInterface(Object object) {
        if (object == null) {
            throw new NullPointerException();
        }
        Class<?> objectClass = object.getClass();
        Class<?>[] implementedInterfaces = objectClass.getInterfaces();
        if (implementedInterfaces.length == 0) {
            throw new IllegalArgumentException(objectClass.getSimpleName() + " implements no interfaces.");
        }
        if (implementedInterfaces.length > 1) {
            throw new IllegalArgumentException(objectClass.getSimpleName() + " implements multiple interfaces.");
        }
        return implementedInterfaces[0];
    }

    public static void main(String... args) {
        Object object = (Closeable) () -> System.out.println("No-op.");
        System.out.println(getDeclaredInterface(object)); // prints 'interface java.io.Closeable'
    }
}
公共类主{
私有静态类getDeclaredInterface(对象){
if(object==null){
抛出新的NullPointerException();
}
Class objectClass=object.getClass();
类[]implementedInterfaces=objectClass.getInterfaces();
if(implementedInterfaces.length==0){
抛出新的IllegalArgumentException(objectClass.getSimpleName()+“未实现任何接口”);
}
如果(implementedInterfaces.length>1){
抛出新的IllegalArgumentException(objectClass.getSimpleName()+“实现多个接口”);
}
返回实现的接口[0];
}
公共静态void main(字符串…参数){
Object Object=(Closeable)(->System.out.println(“No-op.”);
System.out.println(getDeclaredInterface(object));//打印“接口java.io.Closeable”
}
}

使用反射是不可协商的。为了说明问题所在,对示例进行了极大的简化。InfoPanel并不是严格意义上的InfoPanel,它是许多类中的一个,在迭代HashMap时,我实际上无法控制使用哪个类,因此我无法创建列表。这必须通过反思来实现,其他选择是不可能的。答案很好,但我希望它将来能帮助其他人。:)@HristoValchevHristov但是如果对象不是严格意义上的
InfoPanel
,那么您如何/为什么在其上调用方法
attachListener
setInfoTitle
?只有当对象实际具有这些方法时,这些调用才会起作用。如果它们属于超类型的
InfoPanel
,则可以使用该超类型的使用者。我仍然不明白你为什么要使用反射。长话短说:如果它们不存在,我不会给它们打电话。有一个复杂的答案,它确实与问题无关。问题是我没有找到接收ActionListener对象的方法。@HristoValchevHristov如果我不理解这个问题,我将无法帮助您。我可以想到其他使用反射的解决方案,但是他们可以不使用反射做同样的事情。我也不明白为什么要使用这样的映射,而不是聚集在方法名和参数上的某个数据类型的列表。
class Signature {
    private final String name;
    private final Class<?>[] parameters;
    private final Object[] arguments;

    ...
}
List<Signature> signatures = ...;

signatures.add(new Signature("attachListener",
    new Class<?>[] { ActionListener.class },
    new Object[] { e -> System.out.println("working") }));
InfoPanel infoPanel = new InfoPanel();

for(Signature s : signatures) {
    Method m = InfoPanel.class.getDeclaredMethods(s.getName(), s.getParameters());

    m.invoke(infoPanel, s.getArguments());
}
public class Main {
    private static Class<?> getDeclaredInterface(Object object) {
        if (object == null) {
            throw new NullPointerException();
        }
        Class<?> objectClass = object.getClass();
        Class<?>[] implementedInterfaces = objectClass.getInterfaces();
        if (implementedInterfaces.length == 0) {
            throw new IllegalArgumentException(objectClass.getSimpleName() + " implements no interfaces.");
        }
        if (implementedInterfaces.length > 1) {
            throw new IllegalArgumentException(objectClass.getSimpleName() + " implements multiple interfaces.");
        }
        return implementedInterfaces[0];
    }

    public static void main(String... args) {
        Object object = (Closeable) () -> System.out.println("No-op.");
        System.out.println(getDeclaredInterface(object)); // prints 'interface java.io.Closeable'
    }
}