你可以扔什么Java?

传统观点认为只能抛出扩展Throwable对象,但是可以禁用字节码检验器,让Java编译和运行抛出任意对象甚至原语的代码?

我抬头看JVM的运行,它将popup操作数堆栈中的第一个objref; 但它会检查在运行时是否指向Throwable

这取决于你的JVM实现。 根据Java VM规范,如果对象不是Throwable则它是未定义的行为。

objectref 必须是引用types,并且必须引用Throwable类或Throwable子类实例的对象。

在第6.1节“必须的含义”中 :

如果在运行时不满足指令描述中的某个约束(“必须”或“不能”),则Java虚拟机的行为是不确定的。

我用Jasmin汇编程序写了一个testing程序,它执行了等同于throw new Object() 。 Java HotSpot服务器虚拟机引发一个VerifyError

 # cat Athrow.j .source Athrow.j .class public Athrow .super java/lang/Object .method public <init>()V aload_0 invokenonvirtual java/lang/Object/<init>()V return .end method .method public static main([Ljava/lang/String;)V .limit stack 2 new java/lang/Object dup invokenonvirtual java/lang/Object/<init>()V athrow return .end method # java -jar jasmin.jar Athrow.j Generated: Athrow.class # java Athrow Exception in thread "main" java.lang.VerifyError: (class: Athrow, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects 

禁用字节码validation器允许执行行,并且JVM在尝试打印exception的细节时似乎崩溃。 比较这两个程序,第一个抛出一个Exception ,第二个抛出Object是上面的testing程序。 注意它是如何在打印输出中退出的:

 # java -Xverify:none examples/Uncaught Exception in thread "main" java.lang.Exception at examples.Uncaught.main(Uncaught.j) # java -Xverify:none Athrow Exception in thread "main" # 

当然,禁用字节码validation器是危险的。 虚拟机正确写入是为了假定已经执行了字节码validation,因此不必检查指令操作数。 注意:当你规避字节码validation时,你所调用的未定义的行为就像C程序中未定义的行为一样; 什么都可能发生,包括恶魔从你的鼻子飞出。

正如在John的回答中所提到的,你可以禁用validation(把类放在bootclasspath中也应该工作),加载并执行一个抛出非Throwable类的类。

令人惊讶的是,这不一定会导致崩溃!

只要你不隐式或明确地调用Throwable方法,一切都将工作得很好:

 .source ThrowObject.j .class public ThrowObject .super java/lang/Object .method public <init>()V aload_0 invokenonvirtual java/lang/Object/<init>()V return .end method .method public static main([Ljava/lang/String;)V new java/lang/Object dup invokenonvirtual java/lang/Object/<init>()V BeforeThrow: athrow AfterThrow: return CatchThrow: getstatic java/lang/System/out Ljava/io/PrintStream; ldc "Thrown and catched Object successfully!" invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V return .catch all from BeforeThrow to AfterThrow using CatchThrow .end method 

结果:

 % java -Xverify:none ThrowObject Thrown and catched Object successfully! 

禁用字节码validation器 […]

字节码validation是JVM规范的一部分,所以如果你禁用这个(或以其他方式篡改JVM),你可以根据实现来做任何事情(包括抛出原语等)。

从JVM规范引用:

objectref 必须是引用types,并且必须引用Throwable类或Throwable子类实例的对象

也就是说,你的问题可以解释为“如果一个JVM偏离了规范,它可以做怪异的东西,如投掷primitivs” ,答案当然是的。