【问题标题】:All HashMap type values erased in generic class?泛型类中删除的所有 HashMap 类型值?
【发布时间】:2012-09-27 01:40:43
【问题描述】:

为什么以下不编译?编译器对打印行中的+ 符号给出错误。

public class Test<T> {
  HashMap<Integer,Integer> m = new HashMap<Integer, Integer>();
  public static void main(String[] args) {
    Integer zero1 = 0;
    Integer zero2 = 0;
    Test t = new Test();
    t.m.put(1,zero1);
    t.m.put(2,zero2);
    System.out.println(t.m.get(1)+t.m.get(2)==t.m.get(2));
  }
}

我理解类型擦除,但 m 是 HashMap&lt;Integer,Integer&gt;,它根本不应该依赖于类型 &lt;T&gt;。为什么编译器拒绝这个?删除第一行中的&lt;T&gt; 允许编译,但我不明白为什么这不能正常工作。

这是编译器错误还是这种行为背后有什么逻辑?

【问题讨论】:

  • 什么是Testtest1 也是HashMap&lt;Integer,Integer&gt;
  • 你确定你有这个例子吗? main 方法没有引用m,也没有引用T。您得到的确切编译错误是什么......以及在哪里?
  • 糟糕,复制粘贴错误。现已修复。
  • 如果我可以问,为什么不呢?这在 Java 编译器中似乎是意料之外的行为。如果是,那么我想在提交错误报告之前得到专家的确认。如果不是,那么我想知道编译器为什么会这样。在您看来,是什么让这个问题比其他问题更不有趣?
  • +1。这很迷人。当我运行javac -Xlint:unchecked Test.java 时,我收到警告说对put 的调用未选中。由于某种原因,当t 属于原始类型Test 时,编译器会将t.m 视为属于原始类型HashMap

标签: java generics compiler-errors


【解决方案1】:

我没有解释为什么,但行为似乎是正确的定义。§4.8 "Raw Types" of the Java Language Specification 明确指出:

原始类型 C 的构造函数 (§8.8)、实例方法 (§8.4§9.4) 或非静态字段 (§8.3) M 的类型,它不是从其继承的原始类型 C superclasses 或 superinterfaces 是原始类型,对应于 C 对应的泛型声明中其类型的擦除。

在您的示例中,原始类型 C 是 Test(与 Test&lt;Object&gt;Test&lt;Integer&gt; 或诸如此类相反),非静态字段 Mm。由于上述规则,t.m 的类型是原始类型HashMap,而不是HashMap&lt;Integer, Integer&gt;,所以t.m.get(Object) 的返回类型是Object 而不是Integer

【讨论】:

  • 我想知道这种行为的意义是什么......对我来说似乎很奇怪
  • @A.R.S.:如果我不得不猜测的话,我的猜测是,这是语言设计者试图最小化原始类型和参数化类型之间的交互多样性的尝试,因为原始类型是无论如何,基本上只是为了遗留支持。 (此外,听到这解决了在类型系统中会出现的某种弱点——某种看似经过检查但实际上不会被检查的转换——我不会感到震惊——但我不能完全想一个例子说明这可能是如何产生的,所以我不能肯定。)
  • +1 因此,如果您将泛型类用作原始类型,那么您也会在其字段上失去泛型。
  • @A.R.S.:经过进一步审查,我发现规范的该部分为原始类型的非静态内部类本身就是原始类型这一事实提供了一些理由:担心的是所说的非静态内部类可能会引用其包含类型的类型参数,并且基本上他们决定不对非静态内部类这样做的情况做特例。对于非静态字段的情况没有给出相应的理由,但我想我们可以推断他们不希望 Map&lt;Integer, Integer&gt; mMap&lt;T, T&gt; m 有不同的规则?
【解决方案2】:

只需替换您的行:

Test t = new Test();

作者:

Test<Integer> t = new Test<Integer>();

这会奏效的。

【讨论】:

  • 我知道这行得通,我的问题是为什么我写的东西行不通。我认为编译器拒绝这样做是不合理的。
  • 因为似乎类擦除将元素类的擦除强加为同一类型。奇怪,我承认,非常好的问题。
猜你喜欢
  • 2011-05-25
  • 1970-01-01
  • 2014-01-09
  • 2013-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多