2012-06-23 64 views
1

在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>

+0

另请参见[*通用实例创建的类型推导*](http://docs.oracle.com/javase/7/docs/technotes/guides/language/type-in​​ference-generic-instance-creation.html) 。 – trashgod

回答

6

为了表明该方法是一个泛型方法,使用/返回泛型类型。如果他们不存在,编译器会寻找为K具体类型,并命名为V.

+0

这是实际询问的问题的答案:) – Affe

1

因为函数newInstance是通用的,以及,与一般类型ķ并且被转发到HashMapV。它的意思是这样使用:

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

要添加到其他的答案另一个具体类型,与擦除所有的类型都在编译时丢失。但是,编译器首先检查验证,这就是为什么需要类型。

这里是从另一个SO answer擦除之后发生的事情为例:

但使用仿制药的时候,他们转换成编译时检查和执行时间蒙上。所以这个代码:

名单列表=新的ArrayList(); list.add(“Hi”); String x = list.get(0);

被编译成

列表列表=新的ArrayList(); list.add(“Hi”); String x =(String)list.get(0);

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<>();}}

此外,如果类型参数是推断的又是什么顺序。当他们明确表示时,顺序是显而易见的。唯一的(对我来说)解决推断类型参数的顺序问题的方法是它们在代码中声明的顺序。但是如果你只是颠倒了2行代码的顺序(这应该是无关紧要的),你可能会改变破坏构建的公共接口。非常脆弱!

相关问题