我有一个静态方法,我想用它来加载类并在运行时实例化我的对象,但是当我编译时,我收到了这个警告:
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());
}
}
有人可以解释一下吗?
[UPDATE] 以下是方法调用的示例:
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);
答案 0 :(得分:3)
您不能以安全的方式使用字符串来指示类。首先,编译器无法知道字符串集实际上包含完全限定的类名;即使它们是类名,也不能保证名称指定的类是T
的子类。
不是传递一组字符串,而是传入一组类,约束为T
的子类:
Set<Class<? extends T>> classes
然后你可以迭代这些类,并消除任何转换的需要:
for (Class<? extends T> clazz : classes) {
Constructor<? extends T> ctor = clazz.getConstructor();
T t = ctor.newInstance();
list.add(t);
}
如果延迟初始化类的要求是绝对的,那么除了将@SuppressWarnings
适当地添加到此方法之外别无选择,并且希望加载这些字符串的配置是正确的。
答案 1 :(得分:1)
有一个缺失的位。首先,您尝试将每个对象强制转换为T
。如果您事先知道T
,那么在类对象执行时,我没有看到您需要传递一组字符串的原因
假设你是否仍然需要子类的可能性:
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());
}
}