如果在Java中创建一个泛型类(该类具有泛型类型参数),可以使用泛型方法(该方法采用泛型类型参数)吗?
考虑以下示例:
public class MyClass {
public <K> K doSomething(K k){
return k;
}
}
public class MyGenericClass<T> {
public <K> K doSomething(K k){
return k;
}
public <K> List<K> makeSingletonList(K k){
return Collections.singletonList(k);
}
}
正如您对泛型方法所期望的那样,我可以调用任何对象doSomething(K)
的实例:MyClass
MyClass clazz = new MyClass();
String string = clazz.doSomething("String");
Integer integer = clazz.doSomething(1);
但是,如果我尝试在MyGenericClass
不指定泛型类型的情况下使用 的实例,我调用会doSomething(K)
返回一个Object
,而不管K
传入的是什么:
MyGenericClass untyped = new MyGenericClass();
// this doesn't compile - "Incompatible types. Required: String, Found: Object"
String string = untyped.doSomething("String");
奇怪的是,如果返回类型是泛型类,它将编译 - 例如List<K>
(实际上,这可以解释 - 请参阅下面的答案):
MyGenericClass untyped = new MyGenericClass();
List<String> list = untyped.makeSingletonList("String"); // this compiles
此外,如果输入了泛型类,即使只使用通配符,它也会编译:
MyGenericClass<?> wildcard = new MyGenericClass();
String string = wildcard.doSomething("String"); // this compiles
为什么在无类型的泛型类中调用泛型方法不起作用有充分的理由吗?
是否有一些与我缺少的泛型类和泛型方法相关的巧妙技巧?
编辑:
为了澄清,我希望一个无类型或原始类型的泛型类不尊重泛型类的类型参数(因为它们没有被提供)。但是,我不清楚为什么无类型或原始类型的泛型类意味着泛型方法不被尊重。
事实证明,这个问题已经在 SO 上提出,参见这个问题。对此的答案解释说,当一个类是无类型/原始形式时,所有泛型都会从该类中删除 - 包括泛型方法的类型。
但是,对于为什么会这样,并没有真正的解释。所以请允许我澄清我的问题:
- 为什么 Java 会删除无类型或原始类型泛型类上的泛型方法类型?这有充分的理由,还是只是疏忽?
编辑 - JLS 的讨论:
有人建议(在回答上一个 SO 问题和这个问题时)这是在JLS 4.8中处理的,其中指出:
未从其超类或超接口继承的原始类型 C 的构造函数(第 8.8 节)、实例方法(第 8.4 节、第 9.4 节)或非静态字段(第 8.3 节)的类型是对应的原始类型在对应于 C 的泛型声明中擦除其类型。
我很清楚这与非类型化类有何关系——类泛型类型被擦除类型替换。如果类泛型已绑定,则擦除类型对应于这些边界。如果它们未绑定,则擦除类型为 Object - 例如
// unbound class types
public class MyGenericClass<T> {
public T doSomething(T t) { return t; }
}
MyGenericClass untyped = new MyGenericClass();
Object t = untyped.doSomething("String");
// bound class types
public class MyBoundedGenericClass<T extends Number> {
public T doSomething(T t) { return t; }
}
MyBoundedGenericClass bounded = new MyBoundedGenericClass();
Object t1 = bounded.doSomething("String"); // does not compile
Number t2 = bounded.doSomething(1); // does compile
虽然泛型方法是实例方法,但我不清楚 JLS 4.8 是否适用于泛型方法。泛型方法的类型(<K>
在前面的示例中)不是无类型的,因为它的类型由方法参数确定 - 只有类是无类型/原始类型的。