我有一个模板方法,需要使用反射来实例化具有给定类名字符串的类对象。这种情况有点复杂,因为返回类是一个接口的实现,它也使用了一个类型变量。我想传递类名字符串和接口的类型变量的类型,并创建类对象。这是一个示例方法签名:
<T> Class<? extends Foo<T>>
createClassObject(String className, Class<T> classTypeVariable);
是否可以在Java 1.5中实现此方法而不发出任何警告或使用@SuppressWarnings注释?
编辑:感谢Thomas评论,编辑了示例方法签名。
答案 0 :(得分:3)
不,没有任何警告或使用@SuppressWarnings注释就无法实现这一点。那是因为Class.forName()将被输入为Class。任何将其强制转换为具体内容的尝试(例如,Class<? extends Foo<T>>
中的某些内容)都会产生与类型擦除相关的警告。如果您尝试强制转换Class.forName()。newInstance()。
那就是说,我认为这种方法是积极使用@SuppressWarnings的主要例子。在这种情况下,我没有看到使用此注释的任何问题。当然,您可能希望添加一些令Class.forName(className)
确实扩展Foo<T>
的逻辑,以确保铸件是合理的。请注意,此运行时检查不会使方法更脆弱:当您在方法中进行Class.forName()
调用时,您已经存在潜在的运行时类型错误。
答案 1 :(得分:1)
如果返回的类应该是通用的(Bar<T> extends Foo<T>
或诸如此类),那么我非常有信心它是不可能的,因为(由于擦除)类型系统无法在运行时检查 - 如果Class.forName(...)
返回的班级是Class<Bar<T>>
而不是Class<Bar<U>>
或其他类,则为时间。 (实际上只有一个Class
对象代表所有Bar<...>
类型,但类型系统没有表示,因此它假装Class<Bar<T>>
和Class<Bar<U>>
是完全分离不同类型的对象。)你能得到的最接近的东西是这样的:
<T> Class<? extends Iterable<T>> createClassObject
(final String className, final Class<T> clazz) throws Exception
{ return Class.forName(className).asSubclass(getIterableTClass(clazz)); }
@SuppressWarnings("unchecked")
<T> Class<? extends Iterable<T>> getIterableTClass(final Class<T> clazz)
{ return (Class<? extends Iterable<T>>)(Class<?>)Iterable.class; }
使用未经检查的强制转换来诱使编译器认为它有足够的Foo<T>
信息(在这种情况下为Iterable<T>
)来进行asSubclass
检查。
但是,如果返回的类不应该是通用的(Bar extends Foo<String>
或诸如此类),那么我不确定;虽然我知道它们存在,但我从来没有处理过那些与之相关的反射部分。我很确定他们会允许你检查Bar
的继承层次结构,以确定它是否真的扩展Foo<String>
,但我真的不知道他们是否会给你一个方法让编译器意识到你已经这样做了。
答案 2 :(得分:0)
是的,可以做到。在NetBeans IDE 7中,我没有收到任何警告。
更正:抱歉这个不行,没有Class构造。当然,您可以使用ClassLoader,代理类或ASM。
public class Bar<T> extends Foo<T> {
}
这真的很合乎逻辑。线索可能正在进行链式newInstance()。
public <T> Class<? extends Foo<T>> createClassObject(String className, Class<T> classTypeVariable) {
try {
Class<? extends Class> resultType = Bar.class.getClass();
return resultType.getConstructor(classTypeVariable).newInstance();
} catch (InstantiationException ex) {
throw new IllegalStateException(ex);
} catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
} catch (IllegalArgumentException ex) {
throw new IllegalStateException(ex);
} catch (InvocationTargetException ex) {
throw new IllegalStateException(ex);
} catch (NoSuchMethodException ex) {
throw new IllegalStateException(ex);
} catch (SecurityException ex) {
throw new IllegalStateException(ex);
}
}