Java8 Supplier接口提供正确的类型化实例

Ric*_*and 5 java generics

如何使用Java8 Supplier接口重写此工厂方法以提供正确的类型化实例?

我有一个扩展Map的简单界面:

public interface Thingy<K, V> extends Map<K, V> {}
Run Code Online (Sandbox Code Playgroud)

然后我有一个ThingyFactory类,其中包含Thingy所有实现类名的列表:

public final class ThingyFactory {
    Map<String, Class<Thingy<?, ?>>> thingyclasses = new ConcurrentHashMap<>();
    .....

    @SuppressWarnings("unchecked")
    public <K, V> Thingy<K, V> getInstance(String classname) throws ThingyException {
        Thingy<K, V> thingy;
        try {
            thingy = (Thingy<K, V>) thingyclasses.get(classname).newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new ThingyException("Something bad happened: ", e.toString());
        }
        return thingy;
    }
}
Run Code Online (Sandbox Code Playgroud)

我很确定我能够优雅地完成这项任务,并且没有使用供应商界面的SuppressWarnings和类加载器,但我似乎无法使模式非常正确.任何指导赞赏!

Jac*_* G. 1

Thingy因为您使用通配符作为inside的通用类型thingyclasses,所以您实质上是在说:的类型Thingy可以是任何东西;但是,这会阻止编译器推断有关类型的任何信息,因此您需要显式强制转换。您可以Supplier稍微改进它,但您仍然会收到有关未经检查的强制转换的警告:

class ThingyFactory {
    private Map<String, Supplier<Thingy<?, ?>>> providers = new ConcurrentHashMap<>();

    @SuppressWarnings("unchecked")
    public <K, V> Supplier<Thingy<K, V>> getInstance(String classname) {
        return () -> (Thingy<K, V>) providers.get(classname);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您希望它是类型安全的,则需要完全重新设计它,并且仅在编译器能够推断类型时才使用通配符。