【问题标题】:Raw types and type safety [duplicate]原始类型和类型安全[重复]
【发布时间】:2016-10-15 20:32:19
【问题描述】:

所以,假设我有一个简单的列表,如果整数:

List<Integer> intList = new ArrayList<>();
intList.add(1);
intList.add(2);
// intList.add("zxc"); // this will obviously fail

现在让我们将列表包装在另一个列表中:

List<List<Integer>> listOfListOfInt = new ArrayList<>();
listOfListOfInt.add(intList);

一切都好。现在让我们创建方法

private static void method1(List<? extends List> cont) { // [1]
    List<? super Date> data = cont.get(0);  // [2]
    data.add(new Date());
}

基本上我将 DATE 添加到列表中的第一个列表,因为我告诉它将该列表视为List&lt;? super Date&gt;。 当然,由于类型擦除,它可以工作:

    method1(listOfListOfInt);
    System.out.println(intList);

打印[1, 2, Tue Jun 14 23:41:15 BST 2016],所以我的List&lt;Integer&gt; 现在有一个日期。

现在我明白了发生了什么,因为类型擦除 List&lt;? extends List&gt; 变成了一个列表,然后由我决定在其中放入什么,所以我要放入日期。

现在我不太明白的问题是,为什么根本没有“未经检查的分配/调用”的警告?根据 java 编译器,代码是完全类型安全的?

如果在方法 1 中您将 List&lt;? extends List&gt; 替换为 List&lt;List&gt;,或者如果您将 List&lt;? super Date&gt; 替换为 List 等等,它将给出警告,通常您'将收到有关未经检查的分配/调用的警告。但在这种情况下你不会,一切都很好。

更新:显然编译器有警告,但 Intellij Idea 出于某种原因拒绝显示它。我设置了“未经检查的警告”检查,没有忽略任何内容。我认为所有设置都是默认设置。

IntelliJ IDEA 2016.1.3 Build #IC-145.1617,构建于 2016 年 6 月 3 日 JRE: 1.8.0_77-b03 x86 JVM:Oracle Corporation 的 Java HotSpot(TM) Server VM

Update2:它不是重复的,因为问题不在于原始类型的功能,而在于在这种特殊情况下缺乏警告。事实证明这只是一个 IDE 怪癖。

【问题讨论】:

  • 我收到警告。你如何编译你的代码?
  • 这与向后兼容性有关,而不是与擦除有关。为什么很容易将所有事情都归咎于擦除?
  • 您的问题是List&lt;? extends List&gt; 类型中的第二个Listraw。 Raw 与 erasure 不同。 Raw 会失去类型安全性,而擦除不会。你的 IDE(!) 应该已经警告你关于泛型的原始使用。
  • 我不是在“责备”类型擦除,它按预期工作。我只是对这种情况下没有警告感到困惑。
  • 那么我将泛型类型转换为原始类型的警告在哪里呢?请注意,如果您使用稍微不同的 RAW 类型 &lt;List&lt;List&gt;&gt; 而不是 List&lt;? extends List&gt;,则会发出警告。

标签: java generics type-conversion


【解决方案1】:

您的问题是在此声明中使用了 raw 类型:List&lt;? extends List&gt;。第二个List原始。您的问题与类型擦除无关。

在 Eclipse 中输入以下代码时,我收到警告。

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<Integer> intList = new ArrayList<>();
        intList.add(1);
        intList.add(2);
        List<List<Integer>> listOfListOfInt = new ArrayList<>();
        listOfListOfInt.add(intList);
        method1(listOfListOfInt);
        System.out.println(listOfListOfInt);
    }
    private static void method1(List<? extends List> cont) { // [1]
        List<? super Date> data = cont.get(0);  // [2]
        data.add(new Date());
    }
}

来自 Eclipse 的警告

[1] List is a raw type. References to generic type List<E> should be parameterized
[2] Type safety: The expression of type capture#1-of ? extends List needs unchecked conversion to conform to List<? super Date>

使用jdk1.8.0_91 编译时,我得到:

Note: Test.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

添加-Xlint:unchecked,我得到:

Test.java:17: warning: [unchecked] unchecked conversion
                List<? super Date> data = cont.get(0);  // [2]
                                                  ^
  required: List<? super Date>
  found:    CAP#1
  where CAP#1 is a fresh type-variable:
    CAP#1 extends List from capture of ? extends List
1 warning

如您所见,您已被警告,无论是 IDE(在我的例子中是 Eclipse)还是 Java 编译器。

【讨论】:

  • Intellij Idea 在这种情况下没有给我任何警告,但你是对的 - 我刚刚尝试手动编译它,它确实有有意义的警告。所以我猜想Idea设置中某处的一些不起眼的标志是未设置的,尽管我找不到在哪里。这很奇怪。
猜你喜欢
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-12
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 2020-02-27
相关资源
最近更新 更多