当Java文件是接口时,如TestInterface.java:
public interface TestInterface {
void method(String parameterName);
}
Run Code Online (Sandbox Code Playgroud)
我用 编译javac -g TestInterface.java,然后用 反汇编javap -v TestInterface,输出如下:
Classfile /private/tmp/TestInterface.class
Last modified Mar 17, 2022; size 148 bytes
MD5 checksum da2f58afc0eaf77badc94c90de385198
Compiled from "TestInterface.java"
public interface TestInterface
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
#1 = Class #7 // TestInterface
#2 = Class #8 // java/lang/Object
#3 = Utf8 method
#4 = Utf8 (Ljava/lang/String;)V
#5 = Utf8 SourceFile
#6 = Utf8 TestInterface.java
#7 = Utf8 TestInterface
#8 = Utf8 java/lang/Object
{
public abstract void method(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "TestInterface.java"
Run Code Online (Sandbox Code Playgroud)
当Java文件是一个类时,例如TestClass.java:
public class TestClass {
public void method(String parameterName) {
}
}
Run Code Online (Sandbox Code Playgroud)
用 编译javac -g TestClass.java,然后用 反汇编javap -v TestClass,输出如下:
Classfile /private/tmp/TestClass.class
Last modified Mar 17, 2022; size 389 bytes
MD5 checksum 8e124ecce6632ad6e1a5bb45888a3168
Compiled from "TestClass.java"
public class TestClass
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#17 // java/lang/Object."<init>":()V
#2 = Class #18 // TestClass
#3 = Class #19 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 LTestClass;
#11 = Utf8 method
#12 = Utf8 (Ljava/lang/String;)V
#13 = Utf8 parameterName
#14 = Utf8 Ljava/lang/String;
#15 = Utf8 SourceFile
#16 = Utf8 TestClass.java
#17 = NameAndType #4:#5 // "<init>":()V
#18 = Utf8 TestClass
#19 = Utf8 java/lang/Object
{
public TestClass();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LTestClass;
public void method(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this LTestClass;
0 1 1 parameterName Ljava/lang/String;
}
SourceFile: "TestClass.java"
Run Code Online (Sandbox Code Playgroud)
为什么LocalVariableTable不包含在接口的类文件中?
JDK版本:1.8.0_311
因为这不是类文件结构的工作原理。
\n根据JVM 规范,它LocalVariableTable是属性的一部分Code:
\n\n该属性是属性表(\xc2\xa74.7.3)
\nLocalVariableTable中的可选可变长度属性。调试器可以使用它来确定方法执行期间给定局部变量的值。attributesCode
但是,接口方法是抽象的(即具有标志),因此它们首先ACC_ABSTRACT不能具有属性( \xc2\xa74.7.3)。Code
\n\n该属性是结构体表(\xc2\xa74.6)
\nCode中的可变长度属性。属性包含 Java 虚拟机指令和方法的辅助信息 [...]attributesmethod_infoCode如果该方法是 或
\nnative,abstract并且不是类或接口初始化方法,则其结构在其表中method_info不得有属性。Codeattributes
因此,即使它愿意,也不可能为您javac生成抽象接口方法,因为这不会生成正确的类文件。LocalVariableTable
另一种思考方式是,在具体实现该方法之前,该方法的参数实际上并不“存在”。毕竟,抽象方法应该只是一个“需求”而没有“实现”。我真的不明白为什么你会期望有局部变量,因为它们是实现细节。
\n描述LocalVariableTable了变量的范围——可以访问变量的字节码部分。
在类中,非抽象方法的参数有一个范围 - 它可以在整个方法体中访问。即使该方法为“空”,字节码仍然由单个return命令组成。
(实例方法中还有隐式this变量,也可以在方法的整个主体中访问)。
在抽象接口方法(即不是defaultorstatic方法)中,没有可以访问该变量的字节码,因为该方法没有主体,因此没有字节码。因此,没有必要使用LocalVariableTable.
抽象方法(无论是在接口还是类中)只是一个规范,它表示“实现者需要提供这个”。没有实施,没有主体等。
| 归档时间: |
|
| 查看次数: |
240 次 |
| 最近记录: |