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

为什么Eclipse让我将一些Java 7语言特性编译成Java 6类文件?,java,eclipse,ecj,Java,Eclipse,Ecj,我发现在Eclipse中(使用Eclipse编译器),我可以使用一些Java7语言特性,但仍然可以创建Java6类文件。在下图中,您可以看到两个Java 7语言功能已成功编译为Java 6类文件。然而,其他Java7特性(那些被注释掉的特性)不会编译 我的假设是Eclipse正在确定哪些Java 7语言特性与Java 6 JVM兼容,哪些不兼容。例如,泛型类型JComboBox只是一个编译(而不是运行时)特性,因此我可以想象它是如何兼容的。虽然我认为开关字符串特性可能会在字节码上产生差异,并依赖

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

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

我的问题是:

  • Eclipse真的足够聪明,可以知道哪种Java 7语言吗 特性能够被编译成Java6类文件,并且 不是吗

  • 下面的示例显然与1.6源代码不兼容,那么为什么将“源代码兼容性”设置为1.6不会导致错误

  • 这个“技巧”似乎让我至少可以使用一些Java7语言特性,并且仍然可以创建Java6类文件。将javac与源代码1.7和目标代码1.6一起使用会失败,那么为什么会这样呢?Ecilpse编译器有javac没有的特性吗

为了便于比较,这里是我切换到Java6编译器时的结果,正如预期的那样


我想你是对的,当设置为Java 6时,为什么ECJ会编译一些东西而不是其他东西。泛型只是编译成与强制转换相同的东西,所以如果目标设置为Java6,这可能就是它工作的原因


有关javac和ECJ之间的其他差异,请参阅。

我认为有两件事正在发生:

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

  • 第二行可能表示Eclipse编译器中的错误。虽然Java 7的大多数新语言功能都可以在编译器中实现(Android从2013年底就开始实现),但这样做显然与Java 6的源代码不兼容


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

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

    我不知道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>
    
    本质上成为

    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()
    可以由编译器简单地解析

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

    例如,try with resource将不起作用,因为它需要Java 6中不存在的
    AutoCloseable
    接口

    像Lambda表达式这样的特殊功能也需要新类型的字节码

    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;
    }