为什么Eclipse让我将一些Java 7语言特性编译成Java 6类文件?

时间:2014-10-30 15:14:42

标签: java eclipse ecj

我发现在Eclipse中(使用Eclipse编译器)我可以使用一些Java 7语言功能但仍然可以创建Java 6类文件。在下图中,您可以看到两个成功编译为Java 6类文件的Java 7语言功能。但是,那些注释掉的Java 7功能不能编译。

我的假设是Eclipse正在确定哪些Java 7语言功能与Java 6 JVM兼容,哪些不兼容。例如,泛型类型JComboBox只是一个编译(而不是运行时)功能,所以我可以想象它是如何兼容的。切换字符串功能虽然我认为可能会在字节代码中产生差异并依赖新的JVM功能,但我可能是错的......

我的问题:

  • Eclipse真的很聪明,知道哪种Java 7语言 功能可以编译成Java 6类文件和哪些 不是吗?

  • 以下示例显然不是1.6源兼容,那么为什么设置"源兼容性" 1.6不会导致错误?

  • 这个"技巧"似乎让我使用至少一些Java 7语言功能,仍然创建Java 6类文件。使用带有源1.7和目标1.6的javac会失败,那么为什么这样做呢? Ecilpse编译器是否具有javac不具备的功能?

enter image description here

为了便于比较,这是我按预期切换到Java 6编译器时的结果。

enter image description here

4 个答案:

答案 0 :(得分:1)

我认为有两件事情发生了:

  1. 我怀疑第一行(通用JComboBox)是有效的,因为Java 1.7 rt.jar是链接而不是Java 1.6 rt.jar(我有一个设置的项目)使用JavaSE-1.6,在这种情况下,即使使用第一个设置组合,第一行也无法编译。但这是一个类库问题,而不是语言版本问题。 (如果您针对较新的javac编译Java应用程序而不是运行它时,即使使用rt.jar也会遇到很多问题。

  2. 第二行可能代表Eclipse编译器中的一个错误。虽然大多数Java 7新语言功能都可以纯粹在编译器中实现(Android自2013年底开始实现),但这显然与Java 6不兼容源代码。

  3. 因此,简而言之,您在(可能)不寻常的Eclipse配置中发现了至少一个错误。小心,不要依赖它。

答案 1 :(得分:1)

我不知道为什么Eclipse允许这个或者这只是一个bug。 1.7 javac会告诉你

error: strings in switch are not supported in -source 1.6

我也不知道为什么JComboBox有效,

System.out.println(new JComboBox<String>() {}.getClass().getGenericSuperclass());

> javax.swing.JComboBox<java.lang.String>

在运行时具有不应存在的通用信息。允许对非通用类使用泛型应该将IMO拒绝为不兼容。我没有在JVM6上运行代码。也许它甚至会崩溃。

但至少switch在技术上没问题。 http://www.benf.org/other/cfr/java7switchonstring.html表明这只是一个编译器技巧,不需要新的语言功能,API或字节码。

稍微简化的例子:

int java7(String string) {
    switch (string) {
        case "BB":
            return 12;
        case "FRED":
            return 13;
    }
    return 0;
}

基本上变成了

int java6(String string) {
    switch (string.hashCode()) {
        case 2112:
            if (string.equals("BB"))
                return 12;
            break;
        case 2166379:
            if (string.equals("FRED"))
                return 13;
            break;
    }
    return 0;
}

这是基于String#hashCode()的结果被指定并且不得改变的事实。编译器会为您节省一些时间来更快地编写合法代码。

同样适用于钻石经营者:例如: new ArrayList<>()可以简单地由编译器解决。

允许使用相同的7兼容性的android工具允许您使用它。但是,不同之处在于它们使用针对Java 7的.class文件 。 Android需要将.class文件转换为它的内部格式,因此它们的.class到.dex编译器可以使用任何输入工作来生成Android运行时理解的指令。

例如,尝试使用资源不会起作用,因为它需要在Java 6中不存在AutoCloseable接口。

Lambda表达式等特殊功能也需要新类型的字节码。

答案 2 :(得分:0)

我猜你是正确的,为什么ECJ会在设置为Java 6时编译某些东西而不是其他东西。泛型只是编译成与强制转换相同的东西所以如果目标设置为java它可能就是这样的原因6?

有关javac和ECJ之间的其他差异,请参阅What is the difference between javac and the Eclipse compiler?

答案 3 :(得分:0)

这可能是由于您项目的构建路径上配置的JRE系统库与您选择的合规性级别不匹配。通常,您几乎总是希望从执行环境中选择&#34;使用合规性&#34;项目编译器设置中的选项。检查项目的构建路径,看看您是否已将JRE系统库指定为执行环境。