泛型类中的Java泛型方法
如果在Java中创建泛型类(该类具有泛型类型参数),是否可以使用泛型方法(该方法采用泛型类型参数) 考虑以下示例:泛型类中的Java泛型方法,java,generics,language-design,generic-method,raw-types,Java,Generics,Language Design,Generic Method,Raw Types,如果在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 <
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);
}
}
但是,如果我尝试使用MyGenericClass
的实例而不指定泛型类型,
我调用doSomething(K)
返回一个对象
,无论传入了什么K
:
MyGenericClass untyped = new MyGenericClass();
// this doesn't compile - "Incompatible types. Required: String, Found: Object"
String string = untyped.doSomething("String");
奇怪的是,如果返回类型是一个泛型类,它将编译-例如List
(实际上,这可以解释-请参阅下面的答案):
MyGenericClass untyped=新建MyGenericClass();
List List=untyped.makeSingletonList(“字符串”);//这就编译了
此外,如果键入泛型类,即使仅使用通配符,它也会编译:
MyGenericClass<?> wildcard = new MyGenericClass();
String string = wildcard.doSomething("String"); // this compiles
MyGenericClass通配符=新的MyGenericClass();
字符串字符串=通配符。doSomething(“字符串”);//这就编译了
- 在非类型化泛型类中调用泛型方法不起作用有什么好的理由吗
- 是否有一些关于泛型类和泛型方法的巧妙技巧是我所缺少的
- 为什么Java要删除非类型或原始类型泛型类上的泛型方法类型?这是一个很好的理由,还是只是一个疏忽
// 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
//未绑定的类类型
公共类MyGenericClass{
公共T doSomething(T T){return T;}
}
MyGenericClass untyped=新的MyGenericClass();
对象t=非类型化的doSomething(“字符串”);
//绑定类类型
公共类MyBoundedGenericClass{
公共T doSomething(T T){return T;}
}
MyBoundedGenericClass bounded=新的MyBoundedGenericClass();
对象t1=有界。doSomething(“字符串”);//不编译
数字t2=有界。doSomething(1);//编译
虽然泛型方法是实例方法,但我不清楚JLS 4.8是否适用于泛型方法。泛型方法的类型(在前面的示例中为
)不是非类型化的,因为它的类型由方法参数决定-只有类是非类型化/原始类型化的。对于Java泛型,如果使用泛型类的原始形式,则类上的所有泛型,即使是不相关的泛型方法,如makeSingletonList
和doSomething
方法,也会变成原始方法。据我所知,其原因是提供与Java代码编写的预泛型的向后兼容性
如果泛型类型参数
T
,则只需将其从MyGenericClass
中删除,将方法保留为带有K
的泛型。否则,您将不得不接受这样一个事实:类类型参数T
必须提供给您的类,才能在类中的任何其他内容上使用泛型。原因是与泛型前代码的向后兼容性。pre-generics代码没有使用泛型参数,而是使用今天看来是原始类型的参数。预泛型代码将使用Object
引用,而不是使用泛型类型的引用,而原始类型将typeObject
用于所有泛型参数,因此代码确实是向后兼容的
作为例子,考虑这个代码:
List list = new ArrayList();
这是前泛型代码,一旦引入泛型,它就被解释为原始泛型类型,相当于:
List<?> list = new ArrayList<>();
MyGenericClass untyped = new MyGenericClass();
List list = untyped.makeSingletonList("String");
List<String> typedList = list;
在泛型之前使用的
列表
版本使用对象
来引用列表元素,而这个版本也使用对象
来引用列表元素,因此保留了向后兼容性。我找到了完全放弃泛型的一个理由(但这不是很好)。
原因是:泛型可能是有界的。考虑这个类:
public static class MyGenericClass<T> {
public <K extends T> K doSomething(K k){
return k;
}
public <K> List<K> makeSingletonList(K k){
return Collections.singletonList(k);
}
}
公共静态类MyGenericClass{
公共钾剂量计(K){
返回k;
}
公共列表makeSingletonList(K){
返回集合。单音列表(k);
}
}
当使用不带泛型的类时,编译器必须在doSomething
中丢弃泛型。
我认为所有的泛型都被丢弃了,以符合这种行为
makeSingletonList
编译是因为Java执行了从List
到List
的未经检查的强制转换(但编译器显示警告)。这并没有回答基本问题,但解决了为什么makeSingletonList(…)
编译而doSomething(…)
没有:
在MyGenericClass
的非类型化实现中:
MyGenericClass untyped = new MyGenericClass();
List<String> list = untyped.makeSingletonList("String");
MyGenericClass untyped=新建MyGenericClass();
List List=untyped.makeSin
public static class MyGenericClass<T> {
public <K extends T> K doSomething(K k){
return k;
}
public <K> List<K> makeSingletonList(K k){
return Collections.singletonList(k);
}
}
MyGenericClass untyped = new MyGenericClass();
List<String> list = untyped.makeSingletonList("String");
MyGenericClass untyped = new MyGenericClass();
List list = untyped.makeSingletonList("String");
List<String> typedList = list;
MyGenericClass untyped = new MyGenericClass();
List<Integer> list = untyped.makeSingletonList("String"); // this compiles!!!
Integer a = list.get(0);
public class MyGenericClass {
public Object doSomething(Object k){
return k;
}
}
MyGenericClass foo = new MyGenricClass();
NotKType notKType = foo.doSomething(new NotKType());
public class MyGenericClass<T> {
public <K extends KType> K doSomething(K k){
return k;
}
}