为啥一个地方的原始类型会导致其他地方的通用调用点被视为原始类型?

Posted

技术标签:

【中文标题】为啥一个地方的原始类型会导致其他地方的通用调用点被视为原始类型?【英文标题】:Why do raw types in one place cause generic callsites somewhere else to be treated as raw?为什么一个地方的原始类型会导致其他地方的通用调用点被视为原始类型? 【发布时间】:2011-08-31 07:35:01 【问题描述】:

考虑这个例子:

import java.util.*;

class Foo<T> 
  public int baz(List<String> stringlist)  return 1; 
  public int baz(ArrayList<Object> objectlist)  return 2; 

  public static void main(String[] args) 
    Foo<String> foo = new Foo<String>(); // (A)
    //Foo foo = new Foo();               // (B)

    System.out.println(foo.baz(new ArrayList<String>()));
  

为什么它在(A) 中打印1,而在2 中打印(B)

我知道方法解析的工作原理,所以无需向我解释。

我想知道这个“功能”背后的深层动机。 为什么没有关于它的擦除警告? (只有一个关于Foo foo = new Foo()。)

虽然给出了泛型类型,但为什么方法解析使用擦除语义?

【问题讨论】:

【参考方案1】:

这是因为当编译器为resolving overloads时,它会将每个方法视为泛型或非泛型,绝不是两者的混合,所以候选者是:

    Foo&lt;T&gt;.baz(List&lt;String&gt;) Foo&lt;T&gt;.baz(ArrayList&lt;Object&gt;)

如果fooFoo&lt;String&gt;,或者

    Foo.baz(List) Foo.baz(ArrayList)

如果fooFoo

没有Foo.baz(List&lt;String&gt;) 这样的东西。要么考虑所有类型参数,要么不考虑。 (我不知道 JLS 中明确说明了这一点,但这是有道理的,因为将泛型方法视为原始等价物是一种向后兼容的特性。)

在第一种情况下,Foo&lt;T&gt;.baz(List&lt;String&gt;) 匹配但Foo&lt;T&gt;.baz(ArrayList&lt;Object&gt;) 不匹配。

在第二种情况下,两个函数都匹配,并且Foo.baz(ArrayList) 是more specific,所以它被选中。

【讨论】:

【参考方案2】:

如果您只保留单个方法baz(ArrayList&lt;Object&gt;),它甚至不会编译案例(A)(错误:方法不能应用于给定类型)。 我猜ArrayList&lt;String&gt; 不是ArrayList&lt;Object&gt; 的子类。

它在 case (B) 中编译很奇怪,但他们必须做出一些奇怪的决定来保持与非泛型集合的向后兼容性。

【讨论】:

当然不是。 ArrayLists 元素类型未定义为协变。

以上是关于为啥一个地方的原始类型会导致其他地方的通用调用点被视为原始类型?的主要内容,如果未能解决你的问题,请参考以下文章

js笔记 ---- ECMAscript中原始类型与引用类型 注意的地方

javascript原始数据类型compareto引用数据类型--近3天不太会的地方

请朋友们仔细看看,同一个地方,在谷歌地图、百度地图、高德地图等上面标的经纬度数据不同。是为啥呢?

12206. 电缆网络

智能指针std::shared_ptr初始化时可能泄露的地方

为啥我不能将一个 MERN 堆栈项目完全上传到 Github? (在其他地方找不到解决方案)