简体   繁体   中英

Can reflection be used to get a concrete implementing type (e.g. Class<? extends MyInterface>)?

My goal is to reflect all the static classes in a container class and collect them into a map of simpleName -> class .

This can be done 'by hand' with no problem, but I'd really like to do it programatically.

For example, given:

public interface MyInterface {
    void doThing();
}

And a class containing several classes implementing that interface

public class MyStuff {
    public static class One implements MyInterface {...}
    public static class Two implements MyInterface {...}
    public static class Three implements MyInterface {...}
}

The following manually created map works A-OK.

public void demo(String jsonString) {
    Map<String, Class<? extends MyInterface>> myMap = ImmutableMap.of(
        "One", One.class,
        "Two", Two.class,
        "Three", Three.class,
    )

}

And I can use it for useful things such a deserialization with Gson:

MyInterface object = new Gson().fromJson(jsonString, myMap.get("One"))

Now, what I'd like to do is not build that map by hand, but instead use reflection to build it.

Ideally, something along the lines of:

Map<String, Class<? extends MyInterface>> options = new HashMap<>();
for (Class<?> cls : MyStuff.class.getDeclaredClasses()) {
    options.put(cls.getSimpleName(), cls)
}

But this doesn't compile, as getDeclaredClasses is fixed to Class<?> .

Interestingly, Java seems to have all the information it needs during runtime. I can print out each class and see that it is the correct implementing class of MyInterface . I feel like I should be able to get the types I need. However, I can't figure out how to make that final compile-time hop to get a Class<? extends MyInterface> Class<? extends MyInterface>

Is this possible in Java?

If you require that the nested class implements MyInterface , you should check for that, and once you've done that, you can safely cast the value.

private static Map<String, Class<? extends MyInterface>> buildOptions() {
    Map<String, Class<? extends MyInterface>> options = new HashMap<>();
    for (Class<?> cls : MyStuff.class.getDeclaredClasses()) {
        if (MyInterface.class.isAssignableFrom(cls)) {
            options.put(cls.getSimpleName(), cls.asSubclass(MyInterface.class));
        }
    }
    return Collections.unmodifiableMap(options); // Make it immutable
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM