由于java 8,它可以在接口中进行预定方法。其中一些标准实现已经在"标准"接口(例如Charsequence(上实施。如果您尝试读取具有JVM 7的Java 8字节码(例如Java主文件夹的Rt.jar(,则会发生错误。
,例如。类型Java.lang.CharSequence无法解决。
这可能不是级别之间的唯一区别,但我想了解新字节代码的结构。
public interface com.company.ITest {
public void HelloWorld();
Code:
0: getstatic #1 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #2 // String hello world
5: invokevirtual #3 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
此javaCode生产了此bbytecode:
public interface ITest {
default void HelloWorld(){
System.out.println("hello world");
}
}
所以这是我的问题:默认接口对常数池有何影响?
这些标志中的任何一个相关:
constant_methodhandle constant_methodtype contents_invokedy namic
以以下示例:
public interface A {
default void foo(){
System.out.println("Calling A.foo()");
}
}
public class Clazz implements A {
}
从客户端代码的角度来看,默认方法只是普通的虚拟方法。因此,名称 - 虚拟扩展方法。因此,如果示例使用客户端代码,则调用默认方法将在呼叫站点上生成InvokeInterface。
A clazz = new Clazz();
clazz.foo(); // invokeinterface foo()
Clazz clazz = new Clazz();
clazz.foo(); // invokevirtual foo()
在默认方法解决冲突的情况下,当我们覆盖默认方法并希望将调用委派给一个接口之一时,请推断出InvokeSpecial的一个接口,因为我们将专门称为实现:
:public class Clazz implements A, B {
public void foo(){
A.super.foo(); // invokespecial foo()
}
}
public void foo();
Code:
0: aload_0
1: invokespecial #2 // InterfaceMethod A.foo:()V
4: return
如您所见,InvokeSpecial指令用于调用接口方法FOO((。从字节码的角度来看,这也是新事物,因为以前您只能通过超级调用指向类(父类(而不是接口的方法。
这取决于您实际在做什么,您会偶然发现哪种障碍。你说
如果您尝试读取JVM 7的Java 8字节(例如Java Home文件夹的Rt.jar(,则会发生错误。
,例如。类型Java.lang.CharSequence无法解决。
但这甚至无法远程匹配您尝试"读取使用JVM 7"读取Java 8字节码的情况。如果您尝试使用Java 7 JVM加载Java 8类,则通常会获得VerifyError
,并带有一条消息,告诉您不支持类文件版本。
相反,错误消息看起来非常类似于Eclipse编译器的众所周知的错误消息,因为它在读取类文件的字节代码失败时,这与JVM无关。正如本答案中所述,Eclipse似乎并没有在没有找到的类别之间有所作为,或者无法解析的类,只是说" 无法解决"。它似乎也忽略了类文件版本号,因此当它们不使用诸如default
方法之类的较新功能时,它恰好与较新的类文件一起使用。
在技术层面上,差异很小。default
方法与恒定池之间没有关系。游泳池条目类型CONSTANT_MethodHandle
,CONSTANT_MethodType
和CONSTANT_InvokeDynamic
与default
方法无关,它们甚至不是新方法 - 它们已经是标准的一部分(这并不是只能阻止某些工具供应商忽略它们,只要它们做到了不遇到它们(。default
方法只是一种不是abstract
而不是static
的方法,就像普通的public
实例方法一样,而是在接口中。新事物是现在现在。一个简单的类文件解析器不在乎它是读取class
还是interface
的读取不会遇到困难。但是根据工具对数据的作用,它可能会在这样的类文件中(如果尚未停止版本编号停止(,就像较旧的Eclipse编译器一样。
如果JVM的验证者尚未停止在版本号上,则只会扔另一个VerifierError
,说类文件违反了所有方法必须是abstract
。
anurag已经解释了有关默认方法的实现的一些解释,但是我想在您的问题中解决其他观点:
如果您尝试阅读Java 8字节码(例如Java Home的Rt.jar 文件夹(使用JVM 7,发生错误。
例如。类型Java.lang.CharSequence无法解决。
这是因为每个classFile都有一个版本代码,代表其编译为Java的版本。JVM将拒绝任何版本代码高于本身的classFile(但是还可以,但要向后兼容(。
。这意味着,即使对字节码更改的其他内容也没有其他内容,JVM仍然会拒绝从Java的未来版本加载classfiles。您可以使用Java 10编译" Hello World",即使没有新功能或字节差异,Java 9 JVM也会拒绝加载它。