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

pcrecxhr  于 2023-03-21  发布在  Java
关注(0)|答案(4)|浏览(108)

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

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

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

mftmpeh8

mftmpeh81#

使用/返回泛型类型来指示该方法是泛型方法。如果它们不存在,编译器将查找名为K的“真实的类型”(即类或接口)和名为V的另一个实类型。

vq8itlhq

vq8itlhq2#

因为函数newInstance也是泛型的,泛型类型 KV 被转发到HashMap。它的用法是这样的:

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

9avjhtql3#

除此之外,擦除在编译时会丢失所有的类型。然而,编译器会首先检查验证,这就是为什么需要这些类型。
以下是从另一个SO answer擦除后发生的情况的示例:
但是当使用泛型时,它们被转换为编译时检查和执行时强制转换。
列表list = new数组列表();list.add();String x = list.get(0);
被编译成
列表list = new数组列表();list.add();String x =(String)list.get();

13z8s7eq

13z8s7eq4#

编译器能合理地推断类型参数吗?
是的,在示例情况下-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<>();}}
    另外,如果类型参数被推断,那么顺序是什么。当它们被显式声明时,顺序很明显唯一的(对我来说很明显)解决推断类型参数的顺序问题的方法是它们在代码中声明的顺序。(这应该是无关紧要的)你可能会改变公共接口,破坏构建。太脆弱了!

相关问题