2011-10-05 48 views
27

我知道Java 7的运行时功能不适用于Java 6,但自从没有添加新的字节代码新的字节代码invokedynamic仅与非Java语言相关,我想知道如何将Java 7源代码(新的switch语句,钻石操作符)转换为纯Java 6(即能够开始将源代码转换为Java 7而不失去Java 6兼容性)。将Java 7编译为Java 6

任何指针?

+3

我很想知道动机。只是学术兴趣? –

+0

实际上,在Java 7中添加了一个新的字节码:'invokedynamic'(当编译Java源代码时Java编译器不会生成它)。 – Jesper

+0

我认为invokedynamic支持确实意味着添加新的字节码? – SteveD

回答

6

马克在Java 7的javac一个.class输出与1.6.0版本(即0x32)文件

 
printf "\x00\x00\x00\x32" |dd of=Example.class seek=4 bs=1 count=4 conv=notrunc 

(根据http://en.wikipedia.org/wiki/Java_class_file#General_layout

如果你把(使用$ 1名)到j6patch你可以做所有的类文件用:

 
find . -name \*.class |xargs -I {} ./j6patch {} 

我用这对一个大的(〜4.8 MB JAR)的代码库,甚至在Java中使用RetroTranslator 6 jar,因此可以在运行于Java 5的应用程序上使用Java 7语言功能。此外,Java 7编译器(javac)还会执行许多额外的优化(例如,逃逸分析),这显着提高了性能。

使用RetroTranslator-verify -target 1.5和JRE 1.6运行时jar允许验证是否没有使用Java 7运行时功能。

+0

你尝试过吗?它在实践中有多好? –

+0

是的,在一个很大的(〜4.8 MB的jar)代码库上,甚至在Java 6 jar中使用了RetroTranslator,因此可以在运行于Java 5的应用程序上使用Java 7语言功能。此外,Java 7编译器(javac)额外的优化(例如逃逸分析)可以显着提高性能。 – karmakaze

+2

此外,您可以使用RetroTranslator与-verify -target 1.5和JRE 1.6运行时jar来验证是否使用了Java 7运行时。 – karmakaze

11

据我所知,目前没有解决这个问题的方法。最好的办法是扩展retrotranslator来处理Java 1.7构造。钻石操作员应该非常容易,因为它根本不需要字节码修改。

您的语句“没有添加新的字节代码”是不正确的:有一个新的invokedynamic字节代码,更重要的是有几种情况下生成的字节代码在1.6 JRE中无效,所以retrotranslator必须解决该问题。

+0

你能举一个例子,说明生成的字节代码对于Java 6 VM无效吗? 'invokedynamic'不被Java本身使用,它只适用于像Groovy或Jython这样的动态语言(并且两者都可以没有它)。 –

+2

您将不得不经过Java SE 7规范的附件3(http://download.oracle.com/otndocs/jcp/java_se-7-final-eval-spec/index.html),它包含PDF在Java SE 6中的差异。粗略一瞥似乎确实好像所有重大更改(例如新的常量池类型)都与invokedynamic支持相关。 –

+0

问题是字节代码版本号包含在类文件中,所以1.6 JVM不会加载1.7类文件。 –

3

您说得对,invokedynamic指令并未被Java使用,但是还有其他一些可以在Java中使用的相关更改。 Invokedynamic依赖于一种新的“动态链接机制 - 方法处理”,其中对invokevirtual指令也进行了一些更改。您可以在“新动态连杆机构:方法手柄”一节中找到this article的更多详细信息。

方法句柄还提供了更快的反射替代方法,因此在Java中很有用。由于该功能依赖于Java 7 VM,所以不可能将使用方法句柄的代码转换为Java 6。

+0

对引用文章的阅读似乎表明新的'动态链接机制'不支持任何新的字节码,而是支持java.dyn(java.lang.invoke.MethodHandle)运行时支持。当然,应该检查字节码以查看Java 6兼容性没有引用该字节码。 – karmakaze

2

这也可能是一些工作,但试试这个:

Eclipse的Java编译器添加到您的类路径。它位于插件org.eclipse.jdt.core(在文件夹plugins中搜索org.eclipse.jdt.core_*.jar)。

此JAR包含编译器和解析器。您可以自己调用解析器,然后使用use the ASTVisitor来遍历解析树。

然后,您可以修改树并从中创建新的源代码,您可以照常编译。

在编译器生成字节码之前,甚至可以“预处理”AST树;这将为您节省“将源代码写回磁盘并从那里编译”步骤。