【问题标题】:Java 8 needs a cast while Java 7 didn't - enum.getClass/getDeclaringClassJava 8 需要强制转换,而 Java 7 不需要 - enum.getClass/getDeclaringClass
【发布时间】:2014-03-05 14:06:58
【问题描述】:

我意识到 Java 8 仍处于测试阶段,但这个让我觉得很奇怪:

public class Fields<C extends Enum<C>> {

    public Fields(Set<C> columns) {
        // A sample column used to find the universe of the enum of Columns.
        C sampleCol = columns.iterator().next();
        // Java 8 needs a cast here.
        Set<C> allColumns = EnumSet.allOf((/*Class<C>)*/ sampleCol.getClass());
        // ... there's more to this that I've deleted.
    }

}

错误显示:

error: incompatible types: inferred type does not conform to equality constraint(s)
            Set<C> allColumns = EnumSet.allOf(sampleCol.getClass());
    inferred: C
    equality constraints(s): C,CAP#1
  where C is a type-variable:
    C extends Enum<C> declared in class Test.Fields
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Enum from capture of ? extends Enum

这是 Java 8 的错误还是新特性?

【问题讨论】:

  • 我在 Java 7(51) 和 Java 8(b128) 上进行了尝试,在这两种情况下编译器都需要强制转换,当然在这两种情况下仍然处于警告状态。但是当我删除强制转换时,我在两种情况下都会出错(Java 7,8)。我在 IDEA 13 环境下试过了。

标签: java generics java-8


【解决方案1】:

有意思,这是raw types的处理方式的细微变化。

首先,让我们澄清一下您的示例。 Object.getClass 的返回类型比较特殊:

实际结果类型是Class&lt;? extends |X|&gt;,其中|X| 是调用getClass 的表达式的静态类型的擦除。

在这种情况下,X 将是类型参数C,即erasesEnum。所以sampleCol.getClass() 返回Class&lt;? extends Enum&gt;EnumSet.allOf 声明类型参数 E extends Enum&lt;E&gt;,在您的情况下,? extends Enum 被推断为其类型参数。

重要的部分是Enum 是一个原始类型。已经看到使用原始类型会删除看似无关的泛型,例如在这篇文章中:Why won't this generic java code compile? 在他的回答中,Jon Skeet 引用了JLS §4.8(“原始类型”)来涵盖这种不直观的行为。

在您使用 Java 7 的示例中似乎发生了类似的行为:EnumSet.allOf(sampleCol.getClass()) 被允许使用“未经检查的调用”警告进行编译(由于分配生成的原始 EnumSet,这被随后的“未经检查的转换”警告隐藏了到Set&lt;C&gt;)。

问题变成了:在通用通配符的边界中出现的原始类型是否应该允许未经检查的转换? JLS §4.8 没有提到这一点,所以它是模棱两可的。可能这是一个错误,但这似乎是对这种行为的合理收紧。虽然像 Enum 这样的标准原始类型本身可能会出现在遗留 API 中,但像 Class&lt;? extends Enum&gt; 这样的“半生不熟”类型只能出现在泛型之后,因此让它破坏泛型类型检查没有任何意义.

无论如何,我很想看看是否有人可以指出有关此更改的文档 - 我的搜索没有找到任何结果。


关于您的具体代码:您应该改用getDeclaringClass()。编译器无法知道在C 上调用getClass 将完全返回Class&lt;C&gt;;事实上,如果在具有特定常量类的枚举上使用它就不会。这正是Enum 声明该方法的用例。

【讨论】:

  • 感谢您的见解和解决方案 - 非常有趣。奇怪的是,这是我这周第二次需要使用getDeclaringClass - 每个都在完全不同的情况下。我以前从来不需要它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多