匿名类的原始FQDN

时间:2015-09-16 12:49:03

标签: java reflection anonymous-class

我想通过类在Map中存储属性,即地图应该只包含任何运行时类型的一个对象。已有一个当前实现(它是一个现有项目),该机制是用Map<String, Object>实现的。

目前的实施:

import com.foo.IConfiguration;
public class ClientCode {
    private Options options = new Options();
    public void putMethod() {
        options.subOptions(new IConfiguration() {
            public void configure() {}
        });
    }

    public Object getMethod() {
        return options.getSubOption(IConfiguration.class);
    }
}
public class Options {
    private Map<String, Object> map = new HashMap<>();

    public void subOptions(Object subOptionsValue) {
        if (subOptionsValue != null) {
            map.put(subOptionsValue.getClass().getName(), subOptionsValue);
        }
    }
    public Object getSubOption(Class<?> subOptionsClass) {
        return subOptionsClass == null ? null : map.get(subOptionsClass.getName());
    }
}

但是,这不适用于我想要的匿名类。在这种情况下,getName()和相关方法会放置Options$1或类似的东西,而我需要它com.foo.IConfiguration以便我可以在getMethod()中可靠地使用它。

我查看了java.lang.Class的API,但我找不到任何可以回到com.foo.IConfiguration定义的内容。嗯,我可以,但这不是万无一失的:clazz.getInterfaces()提供了一个接口数组,这里很好,但我也可以创建一个new Object() {}或本地类,或者一个普通的公共类。

那么有没有一种不错的方法可以明确地检索匿名类的接口或超类的FQDN?

3 个答案:

答案 0 :(得分:2)

匿名类没有您可以信赖的完全限定名称,但您可以通过ob.getClass().isAnonymousClass()检查对象是否是匿名类。然后,只有返回true才能检索超类或超级接口。

你应该至少考虑处理lambdas,即使你还没有在Java 8上运行它。

答案 1 :(得分:1)

正如对biziclop建议的评论中所承诺的那样,我正在提交我投入使用的代码。这似乎适用于常规类和匿名类,无论它们是实现接口还是扩展超类。

public void subOptions(Object subOptionsValue) {
    if (subOptionsValue != null) {
        Class<?> clazz = subOptionsValue.getClass();
        String clazzName;
        if (clazz.isAnonymousClass()) {
            // not sure if getInterfaces can return null
            if (clazz.getInterfaces() != null && clazz.getInterfaces().length > 0) {
                // anonymous classes can implement only one interface
                clazzName = clazz.getInterfaces()[0].getName();
            } else {
                clazzName = clazz.getSuperclass().getName();
            }
        } else {
            clazzName = clazz.getName();
        }
        map.put(clazzName, subOptionsValue);
    }
}
编辑:处理lambdas更加困难,因为没有明确的方法来挑出lambda实现,但是我们可以通过跟随How to correctly determine that an object is a lambda?和更改

来足够接近(至少我的目的)
if (clazz.isAnonymousClass()) {...}

if (clazz.isAnonymousClass() || clazz.isSynthetic()) {...}

答案 2 :(得分:0)

我建议你通过它的所有接口,基类和接口的超级接口等将对象多次放入map中。

例如你有

interface I1 {}
interface I2 extends I1 {}
class C1 {}
class C2 extends C1 implements I2{}

您将C2的实例放入Options

您可能希望通过I1.classC1.class

检索它

但是在这种情况下,如果你有两个实现一个接口的类,你需要为可能的歧义做好准备。

对于这种情况,您可能希望能够显式指定可用于检索特定类的类和接口列表。