字节码功能在Java语言中不可用

时间:2011-07-26 08:39:36

标签: java jvm bytecode

Java语言代码中是否存在(Java 6)您无法在Java语言中执行的操作?

我知道两者都是图灵完整的,所以读“可以做”为“可以做得更快/更好,或者只是以不同的方式”。

我正在考虑像invokedynamic这样的额外字节码,这些字节码不能使用Java生成,除非特定的字节码用于将来的版本。

8 个答案:

答案 0 :(得分:60)

据我所知,Java 6支持的字节码中没有主要功能,这些功能也无法从Java源代码访问。主要原因显然是Java字节码的设计考虑了Java语言。

但现有的Java编译器并没有产生一些功能:

  • ACC_SUPER flag

    这是一个可以在类上设置的标志,它指定如何为此类处理invokespecial字节码的特定边案例。它是由所有现代Java编译器设置的(其中“modern”是> = Java 1.1,如果我没记错的话)并且只有古老的Java编译器生成了这个未设置的类文件。此标志仅出于向后兼容性原因而存在。请注意,从Java 7u51开始,由于安全原因,ACC_SUPER将被完全忽略。

  • jsr / ret字节码。

    这些字节码用于实现子例程(主要用于实现finally块)。他们是no longer produced since Java 6。它们被弃用的原因是它们使静态验证复杂化并没有太大的好处(即使用的代码几乎总是可以通过正常跳转重新实现而且开销非常小)。

  • 在类中只有两个方法只有不同的返回类型。

    Java语言规范在它们的返回类型(即同名,相同的参数列表,......)中只有 时,不允许同一类中的两个方法。但是,JVM规范没有这样的限制,因此类文件可以包含两个这样的方法,使用普通的Java编译器就无法生成这样的类文件。 this answer中有一个很好的例子/解释。

答案 1 :(得分:12)

以下是一些可以用Java字节码完成但不能用Java源代码完成的功能:

  • 从方法中抛出已检查的异常,而不声明方法会抛出它。已检查和未检查的异常只能由Java编译器检查,而不是JVM。因此,例如Scala可以在不声明方法的情况下从方法中抛出已检查的异常。虽然使用Java泛型,但有一个名为sneaky throw的解决方法。

  • Joachim's answer中已经提到的类中有两个方法只有不同的返回类型:Java语言规范不允许在同一个类中使用两个方法它们的返回类型只有 (即同名,相同的参数列表,......)。但是,JVM规范没有这样的限制,因此类文件可以包含两个这样的方法,使用普通的Java编译器就无法生成这样的类文件。 this answer中有一个很好的例子/解释。

答案 2 :(得分:6)

  • GOTO可与标签一起使用,以创建您自己的控制结构(for while等除外)
  • 您可以覆盖方法
  • 中的this局部变量
  • 结合这两个你可以创建创建尾调用优化字节码(我在JCompilo中执行此操作)

作为相关点,如果使用debug(Paranamer does this by reading the bytecode

进行编译,则可以获取方法的参数名称

答案 3 :(得分:4)

也许this document中的第7A节是有意义的,虽然它是关于字节码陷阱而不是字节码功能

答案 4 :(得分:3)

在Java语言中,构造函数中的第一个语句必须是对超类构造函数的调用。字节码没有这个限制,相反规则是在访问成员之前必须为对象调用超类构造函数或同一类中的另一个构造函数。这应该允许更多的自由,例如:

  • 创建另一个对象的实例,将其存储在局部变量(或堆栈)中,并将其作为参数传递给超类构造函数,同时仍保留该变量中的引用以供其他用途。
  • 根据条件调用其他不同的构造函数。这应该是可能的:How to call a different constructor conditionally in Java?

我没有测试过这些,所以如果我错了请纠正我。

答案 5 :(得分:2)

您可以使用字节代码而不是普通的Java代码来生成可以在没有编译器的情况下加载和运行的代码。许多系统都有JRE而不是JDK,如果你想动态生成代码,生成字节代码可能更好,如果不是更容易,而不是Java代码必须先编译才能使用。

答案 6 :(得分:1)

当我是I-Play时,我编写了一个字节码优化器(它旨在减少J2ME应用程序的代码大小)。我添加的一个功能是使用内联字节码的能力(类似于C ++中的内联汇编语言)。我设法通过使用DUP指令减少作为库方法一部分的函数的大小,因为我需要两次该值。我也有零字节指令(如果你正在调用一个接受char的方法而你想传递一个int,你知道不需要进行转换我添加了int2char(var)来替换char(var)它会删除i2c指令减少了代码的大小。我也做了浮点数a = 2.3;浮点数b = 3.4;浮点数c = a + b;并且它会被转换为固定点(更快,也有些J2ME没有支持浮点)。

答案 7 :(得分:0)

在Java中,如果您尝试使用受保护的方法覆盖公共方法(或任何其他访问减少),则会收到错误:"尝试分配较弱的访问权限"。如果使用JVM字节码执行此操作,则验证程序可以正常使用它,您可以通过父类调用这些方法,就好像它们是公共的一样。