【发布时间】:2013-08-01 18:15:31
【问题描述】:
如果在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);
}
}
正如您对泛型方法所期望的那样,我可以使用任何对象在 MyClass 的实例上调用 doSomething(K):
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 上提出,c.f. this question。对此的答案解释说,当一个类是无类型的/以其原始形式时,所有泛型都从该类中删除 - 包括泛型方法的类型。
但是,对于为什么会这样,并没有真正的解释。所以请允许我澄清一下我的问题:
- 为什么 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>)不是无类型的,因为它的类型由方法参数决定——只有类是无类型/原始类型的。
【问题讨论】:
-
@PaulBellora - 谢谢。第一个非常相关 - 尽管我对 SO 的大量搜索没有找到它,所以感谢您的参考。第二个不太相关,因为它只涵盖泛型类,而不是泛型方法。
-
抱歉,有点OT。但是我尝试搜索它,静态类是一个新结构吗? AFAIK 它不会在 Java 6 中编译(它会在 Java 7 中编译吗?)。
-
@hajder - 抱歉,我最初将这些作为嵌套类写在测试类中(因此使它们成为静态),并且在我对问题进行 C&P 时忽略了删除它们。现已移除。
标签: java generics language-design generic-method raw-types