Java泛型代码在Eclipse中编译通过,但在命令行中却无法编译。

3

我知道过去有几个关于在Eclipse中编译但在命令行中不能编译的问题,但我还没有找到解决我的问题的答案。

特别是,我认为我能够设置eclipse使用我的系统编译器,但这仍然没有解决问题。

我目前正在检查:'首选项 -> Java -> 已安装的JRE'。

这里只包含一个JRE,即我的系统JRE。

以下是问题的具体信息

我有一个Java泛型类,它以Enum类型作为参数,如下所示:

public class MyClass<T extends Enum<T>>

在类的某个地方,我将一个已知的枚举值与T的值进行比较。因此,例如,假设我有以下枚举:

public enum OtherEnum{
 a,
 b
}

然后我进行测试:

protected void foo(T enumVal){
    if(enumVal == OtherEnum.a){
        // do something
    }
    else if(enumVal == OtherEnum.b){
        // do something else
    }
}

在Eclipse中编译没有问题,但在命令行javac中出现以下错误:

incomparable types: T and OtherEnum

我尝试在两个使用Java 1.6(1.6.0_26和1.6.0_16)变体的系统上进行操作。一个是Mac,另一个是Linux。它们都给出了同样的错误,而Eclipse则可以顺利编译。

所以:

  1. 如何确定Eclipse正在使用哪个编译器?

  2. 这里到底是什么问题?

谢谢!


也许这可以帮助你:https://dev59.com/0XM_5IYBdhLWcg3w6HvT - sizzle
你使用任何外部的 .jar 文件吗? - dimme
请发布一个 SSCEE 来演示您遇到的问题。 - Brian Roach
@szielenski 谢谢,这是一篇非常有趣的文章。我相信问题是相关的,但我不确定如何在我的情况下处理它。我现在正在更深入地研究它。 - Dana
@Dimme 不,没有任何外部因素,这只是一个小项目。 - Dana
4个回答

5

这是应该被接受的答案,因为使用 JDK 7+ 进行编译可以在不更改源代码级别兼容性的情况下编译通过,而使用 JDK 6 则会失败。 - Valentin

1
非常有趣的问题。
以下代码无法编译。
    Integer x = null;
    String s = null;
    if(x==s){}   // error: incomparable types

JLS3#15.21.3 [1] 表示:

如果通过强制类型转换(§5.5)将任一操作数的类型转换为另一个操作数的类型是不可能的,则会在编译时出现错误。

显然,前面的例子看起来像是一个明显的编程错误,因此规范试图捕捉它并警告程序员。如果 Java 想要允许它,就不会有任何麻烦。该示例的解决方法是将一侧转换为 Object

回到您的问题,我们需要决定是否可以将 OtherEnum 转换为 T,或者反过来。这是一个令人惊讶的难题;按照 JLS3#5.5 [2] 的程序,答案是否定的。

关键在于是否可以将 OtherEnum 转换为 Enum<T>;然后我们可以找到超类型 X=Enum<OtherEnum>Y=Enum<T>,它们是可证明的不同参数化类型。因此,转换是非法的。

好吧,这样的规范太详细了,谁会在正常情况下关心呢?

您可以通过将一个枚举值强制转换为Object来解决这个问题,例如(Object)enumVal == OtherEnum.a

Java 7的行为不同,它会编译您的代码。我不知道原因。可能是Java7引入了一个新的bug。或者它有一个新的规范允许这段代码(但我们无法访问新的规范)。另一个可能性是我误解了“可证明不同参数化类型”的术语;然而,在没有正式定义的情况下,直观上Enum<OtherEnum>Enum<T>是不同的。

参考资料

[1] http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.21.3

[2] http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#20232


为什么要绕过它呢?这与实际值的评估没有任何关系。 - apesa

0

Eclipse使用自己的Java编译器实现(ECJ),与javac无关。

Java的Eclipse编译器:

一种增量Java编译器。它是作为Eclipse构建器实现的,基于从VisualAge for Java编译器演变而来的技术。特别地,它允许运行和调试仍包含未解决错误的代码。


哇,我没想到这个。这很有趣,因为我已经通过Eclipse使用了我的代码的这个特定部分,所以那里一定有些东西在起作用。而且我仍然不确定最初是什么导致了错误。 - Dana

0

单独的编译器...使用==会强制进行更严格的编译时检查,因此在 CL 中它强制执行类型比较并出错。在 Eclipse 中,您可以管理编译时的设置并放宽限制。

您可以尝试 Enum.equals(),它可能不会强制执行如此严格的编译时类型比较。这只是一个想法。


成功了!但我还是不明白,为什么原始版本不起作用?==的两个部分都被定义为枚举,为什么类型检查失败? - Dana
由于您正在比较字符串“Content”的值,而不是字符串“Identity”的内存地址。这是有道理的。 - apesa
在枚举的情况下,标识不应该相同吗? - Dana
使用 == 操作符比较 EnumVal 的内容是否相等。CL 编译器报错,因为 EnumVal 是一个不可比较的类型。我猜想如果你对 EnumVal 进行更严格的类型转换,可能就不会在编译时出错了。 - apesa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接