请考虑以下代码:
public class Generics {
C c; // initialized at runtime
public void testGenericsCall(Object o) {
c.myMethod(o);
}
}
class C<E> {
public void myMethod(E input) {
}
}
这是有效的,但我收到警告,因为参数化类C与原始类型一起使用。我不能使用像
这样的声明C<String> c;
因为C的类型仅在运行时才知道。我也无法在类Generics中添加类型参数,因为我需要在知道C类型之前创建此类的对象。声明
C<?> c;
或
C<? extends Object> c;
对于编译器是可以的,但是然后方法testGenericsCall不能编译(“实际参数java.lang.Object无法转换为通过方法调用转换捕获#1?”)< / p>
处理这种情况的最佳方法是什么?
编辑:请注意,当我实际(在运行时)创建C的实例时,我知道它的类型参数,这部分代码是类型安全的并且运行良好。在真正的代码中,我没有一个单独的“C”类,而是一系列相互关联的类,并且泛型绝对有用(即使在这个简化的例子中这并不明显 - 所以请不要只告诉我不要使用泛型:)。我已经有了编译时类型安全,但不是这里,而是在C和其他类之间(这里没有显示)。
我看到在这种情况下我无法在编译时检查类型参数,这就是我尝试声明它C<?> c
的原因。这里我正在寻找在没有编译器警告的情况下桥接通用代码和非通用代码的最佳方法。
答案 0 :(得分:3)
由于type erasure,在运行时无法使用泛型。您必须通过检查类型或任何内容(可能是反射)以编程方式处理您的数据类型。
答案 1 :(得分:2)
你可以做到。但通过肮脏的技巧和反思。以下面的代码为例。礼貌here:
class ParameterizedTest<T> {
/**
* @return the type parameter to our generic base class
*/
@SuppressWarnings("unchecked")
protected final Class<T> determineTypeParameter() {
Class<?> specificClass = this.getClass();
Type genericSuperclass = specificClass.getGenericSuperclass();
while (!(genericSuperclass instanceof ParameterizedType) && specificClass != ParameterizedTest.class) {
specificClass = specificClass.getSuperclass();
genericSuperclass = specificClass.getGenericSuperclass();
}
final ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
final Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
return (Class<T>) firstTypeParameter;
}
}
//change the type of PrameterizedTest<Integer> to Parameterized<String> or something to display different output
public class Test extends ParameterizedTest<Integer>{
public static void main(String... args){
Test test = new Test();
System.out.println(test.determineTypeParameter());
}
}
在运行时,您将获得Type参数。因此,在您的课程中,您必须定义一个Class
对象,如上所述获取该类。然后使用Class.newInstance
获得一个新对象。但是你必须手动处理类型转换等等。
问题是:这一切都值得吗?
根据我的说法,通过使用泛型类型中的边界并与绑定类型接口,可以避免大部分内容