为什么类型参数必须重复两次?

时间:2012-06-23 22:02:34

标签: java

在Java中的这个静态函数中,为什么必须在第1行重复<K, V>

public static <K, V> HashMap<K, V> newInstance() {
  return new HashMap<K, V>();
} 

我理解为什么HashMap<K, V>是必要的,因为该函数返回一个HashMap,其泛型类型K和V分别作为键和值。但是,为什么函数签名中需要第一个<K, V>

4 个答案:

答案 0 :(得分:6)

要指示该方法是泛型方法,请使用/返回泛型类型。如果它们不存在,编译器将查找名为K的具体类型,以及另一个名为V的具体类型。

答案 1 :(得分:1)

因为函数newInstance也是通用的,通用类型 K V 会被转发到HashMap。它意味着像这样使用:

HashMap<Integer, String> map = newInstance<Integer,String>();

答案 2 :(得分:1)

要添加到其他答案,删除所有类型都会在编译时丢失。但是,编译器首先检查验证,这就是为什么需要这些类型的原因。

以下是从另一个SO answer中删除后发生的事情的示例:

但是当使用泛型时,它们会被转换为编译时检查和执行时转换。所以这段代码:

List list = new ArrayList(); list.add( “你好”); String x = list.get(0);

编译成

List list = new ArrayList(); list.add( “你好”); String x =(String)list.get(0);

答案 3 :(得分:1)

编译器能否合理推断出类型参数?

在示例情况下是 - 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<>();}}可以类型推断为以下之一:

  1. class X <K extends Object , V extends Object> { HashMap<K,V>newInstance(){return new HashMap<>();}}
  2. class X <K extends Object > { < V extends Object > HashMap<K,V>newInstance(){return new HashMap<>();}}
  3. class X <V extends Object> { < K extends Object > HashMap<K,V>newInstance(){return new HashMap<>();}}
  4. class X { <K extends Object , V extends Object> HashMap<K,V>newInstance(){return new HashMap<>();}}
  5. 此外,如果推断出类型参数,那么订单是什么。明确说明时,顺序很明显。解决推断类型参数的顺序问题的唯一(显而易见的)方法是它们在代码中声明的顺序。但是如果你只是颠倒2行代码的顺序(这应该是无关紧要的),你可能会改变破坏构建的公共接口。太脆了!