泛型类中的 Java 泛型方法
如果在 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,c.f.这个问题上提出来了。对此的回答解释了,当一个类是非类型化/以其原始形式时,所有泛型都从类中删除 - 包括泛型方法的类型化。
但是,对于为什么会这样,并没有真正的解释。因此,请允许我澄清我的问题:
- 为什么 Java 要删除非类型化或原始类型泛型类上的泛型方法类型?这是有充分理由的,还是只是一个疏忽?
编辑 - 讨论JLS:
有人建议(在回答前面的SO问题和这个问题时)在JLS 4.8中处理这个问题,其中指出:
未从其超类或超接口继承的原始类型 C 的构造函数 (§8.8)、实例方法 (§8.4、 §9.4) 或非静态字段 (§8.3) M 是原始类型,该类型对应于在对应于 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>