首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么Eclipse允许我将一些Java 7语言特性编译成Java 6类文件?

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

Stack Overflow用户
提问于 2014-10-30 15:14:42
回答 4查看 258关注 0票数 5

我发现在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没有的特性吗?

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

EN

回答 4

Stack Overflow用户

发布于 2014-10-30 15:47:11

我想有两件事正在发生:

  1. 我怀疑第一行(使用泛型JComboBox)是因为Java1.7 rt.jar是链接的,而不是Java1.6 rt.jar (我有一个用JavaSE-1.6安装的项目,在这种情况下,即使使用第一个设置组合,第一行也不会编译)。但这是类库问题,而不是语言版本问题。(与运行javac时相比,如果您使用较新的rt.jar编译Java应用程序,即使使用Java也会遇到很多问题)。
  2. 第二行可能表示Eclipse编译器中的一个bug。虽然Java 7的大部分新语言特性完全可以在编译器中实现( Android自2013年底以来就这样做了),但这样做显然与Java 6不兼容。

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

票数 1
EN

Stack Overflow用户

发布于 2014-10-30 17:37:14

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

代码语言:javascript
运行
复制
error: strings in switch are not supported in -source 1.6

我也不知道为什么JComboBox能工作,

代码语言:javascript
运行
复制
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或字节码的编译器技巧。

略为简化的例子:

代码语言:javascript
运行
复制
int java7(String string) {
    switch (string) {
        case "BB":
            return 12;
        case "FRED":
            return 13;
    }
    return 0;
}

从本质上

代码语言:javascript
运行
复制
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工具,允许相同的半7兼容性,允许你使用它。然而,不同之处在于,它们使用的是针对Java 7的.class文件。安卓需要将.class文件转换成它的内部格式,这样他们的.class到.dex编译器就可以使用任何输入来生成被安卓运行时理解的指令。

例如,使用资源的尝试就无法工作,因为它需要Java6中不存在的AutoCloseable接口。

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

票数 1
EN

Stack Overflow用户

发布于 2014-10-30 15:23:33

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

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26656774

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档