如何将通配符 (?) 转换为通用类型 T?

How to cast Wildcard (?) to a Generic type T?

我有一个静态方法,我想用它来加载 类 并在运行时实例化我的对象,但是当我编译时,我收到了这个警告:

warning: [unchecked] unchecked cast
            T t = (T) ctor.newInstance();
required: T
found:    CAP#1
where T is a type-variable:
    T extends Object declared in method <T>forName(String,Set<String>)
    where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 warning

代码如下:

public static <T> Set<T> forName(String modulePath, Set<String> classes) throws InvalidModuleException{
    try {
        ClassLoader cl = new URLClassLoader(new URL[]{new URL(modulePath)});

        Set<T> list = new HashSet<>(classes.size());
        for (String className : classes) {
            Class<?> clazz = (Class<?>) Class.forName(className, true, cl);
            Constructor<?> ctor = clazz.getConstructor();
            T t = (T) ctor.newInstance();
            list.add(t);
        }
        return list;    
    } catch (MalformedURLException | ReflectiveOperationException ex) {
        throw new InvalidModuleException(ex.getMessage());
    }
}

谁能给我解释一下?

[更新] 这是方法调用的示例:

HashSet<String> set = new HashSet<>();
h.add("fully_classfied_classname_readed_from_file"); //Class that extends AbstractApplication
Set<AbstractApplication> abs = Apps.forName("plugins/module.jar", set);

您不能以安全的方式使用字符串来指示 classes。一方面,编译器无法知道字符串集实际上包含 fully-qualified class 个名称;即使它们是 class 个名称,也不能保证名称指定的 class 是 T.

的子class

不是传递一组字符串,而是传递一组 classes,限制为 T:

的子classes
Set<Class<? extends T>> classes

然后您可以迭代这些 classes,并删除任何强制转换的需要:

for (Class<? extends T> clazz : classes) {
  Constructor<? extends T> ctor = clazz.getConstructor();
  T t = ctor.newInstance();
  list.add(t);
}

如果延迟初始化 classes 的要求是绝对的,你别无选择,只能适当地添加 @SuppressWarnings 到这个方法,并希望加载这些字符串的配置是正确的。

少了一位。首先,您尝试将每个对象类型转换为 T。如果你预先知道 T,我看不出你需要向谁传递一组字符串的原因,而 class 对象会做

假设如果有可能sub-classes还需要:

public static <T> Set<? extends T> forName(String modulePath, Set<String> classes, Class<T> claz) throws InvalidModuleException{
    try {
    ClassLoader cl = new URLClassLoader(new URL[]{new URL(modulePath)});

    Set<T> list = new HashSet<>(classes.size());
    for (String className : classes) {
        Class<?> clazz = Class.forName(className, true, cl);
        Constructor<?> ctor = clazz.getConstructor();
        Object obj = ctor.newInstance();
        list.add(claz.cast(obj));
    }
    return list;
} catch (MalformedURLException | ReflectiveOperationException | ClassCastException ex) {
    throw new InvalidModuleException(ex.getMessage());
}
}