在Java中的这个静态函数中,为什么在第1行中必须重复<K, V>
?为什么类型参数必须重复两次?
public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
我明白为什么HashMap<K, V>
是必要的,因为该函数返回分别与泛型类型K和V一个HashMap的键和值。但是,函数签名中为什么需要第一个<K, V>
?
在Java中的这个静态函数中,为什么在第1行中必须重复<K, V>
?为什么类型参数必须重复两次?
public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
我明白为什么HashMap<K, V>
是必要的,因为该函数返回分别与泛型类型K和V一个HashMap的键和值。但是,函数签名中为什么需要第一个<K, V>
?
因为函数newInstance
是通用的,以及,与一般类型ķ并且被转发到HashMap
V。它的意思是这样使用:
HashMap<Integer, String> map = newInstance<Integer,String>();
要添加到其他的答案另一个具体类型,与擦除所有的类型都在编译时丢失。但是,编译器首先检查验证,这就是为什么需要类型。
这里是从另一个SO answer擦除之后发生的事情为例:
但使用仿制药的时候,他们转换成编译时检查和执行时间蒙上。所以这个代码:
名单列表=新的ArrayList(); list.add(“Hi”); String x = list.get(0);
被编译成
列表列表=新的ArrayList(); list.add(“Hi”); String x =(String)list.get(0);
能编译合理地推断类型参数?
是在本例的情况 - static HashMap<K,V>newInstance(){return new HashMap<>();}
显然简称static < K extends Object , V extends Object > HashMap<K,V>newInstance()return new HashMap<K,V>();}
。
但是,如果你的编译器推断类型的参数,那么你的代码仍然会当你敲错类名编译均匀。 static void setName (Sting name)
可能是错误的,但您的编译器会假设您的意思是<Sting extends Object> static void setName (Sting name);
通过运行时擦除的魔术将相当于static void setName (Object name) ;
。
如果该方法不是静态的,那么推论成为问题。 class X { HashMap<K,V>newInstance(){return new HashMap<>();}}
可能是类型推断为以下之一:
class X <K extends Object , V extends Object> { HashMap<K,V>newInstance(){return new HashMap<>();}}
class X <K extends Object > { < V extends Object > HashMap<K,V>newInstance(){return new HashMap<>();}}
class X <V extends Object> { < K extends Object > HashMap<K,V>newInstance(){return new HashMap<>();}}
class X { <K extends Object , V extends Object> HashMap<K,V>newInstance(){return new HashMap<>();}}
此外,如果类型参数是推断的又是什么顺序。当他们明确表示时,顺序是显而易见的。唯一的(对我来说)解决推断类型参数的顺序问题的方法是它们在代码中声明的顺序。但是如果你只是颠倒了2行代码的顺序(这应该是无关紧要的),你可能会改变破坏构建的公共接口。非常脆弱!
另请参见[*通用实例创建的类型推导*](http://docs.oracle.com/javase/7/docs/technotes/guides/language/type-inference-generic-instance-creation.html) 。 – trashgod