簡體   English   中英

Java反射獲取匿名類的原始接口

[英]Java reflection get anonymous class' origin interface

我有以下 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 的類,它具有以下方法。

public void attachListener(ActionListener al) {
    this.button.addActionListener(al);
}

public void setInfoTitle(String name) {
    ((TitledBorder) this.getBorder()).setTitle(name);
}

稍后我遍歷 HashMap 的鍵。

InfoPanel infoPanel = new InfoPanel();

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

    method.invoke(infoPanel, key));
}

可以想象,當鍵是 String 對象時沒有問題,當 getDeclaredMethod 搜索具有 MainPanel$1 類型參數的方法 attachListener 時出現問題,因為 .getClass 返回 MainPanel$1,因為它是動態創建的匿名類。 我的問題是 - 如何找到用於創建用於對象實例化的匿名類的接口?

簡單回答你的問題

如何找到用於創建用於對象實例化的匿名類的接口?

在下面的代碼片段中。 但請注意,您的方法可能非常有問題,如果可能,您應該嘗試重構它。

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'
    }
}

您不需要為此使用反射。 您可以使用List<Cosumer<InfoPanel>> ,它基本上是一個函子列表,每個函子都以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"));

稍后,當您創建InfoPanel

InfoPanel infoPanel = new InfoPanel();

commandList.forEach(command -> command.accept(infoPanel));

當然,這利用了 Java8,但如果需要,Java7 也可以實現同樣的功能。


如果您堅持使用反射,您可以創建一個存儲預期參數類型以及方法名稱和參數的數據類型:

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());
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM