为什么Java接口用javac -g编译的类文件中没有LocalVariableTable?
当Java文件是一个接口时,例如TestInterface.java
:
public interface TestInterface {
void method(String parameterName);
}
我用javac -g TestInterface.java
编译,然后用javap -v TestInterface
反汇编code>,输出如下:
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"
而当Java文件是类时,如TestClass.java
:
public class TestClass {
public void method(String parameterName) {
}
}
用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"
为什么接口的类文件中没有包含LocalVariableTable
?
JDK版本:1.8.0_311
When the Java file is a interface, such as TestInterface.java
:
public interface TestInterface {
void method(String parameterName);
}
I compile with javac -g TestInterface.java
and then disassemble with javap -v TestInterface
, the output is as follows:
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"
And when the Java file is a class, such as TestClass.java
:
public class TestClass {
public void method(String parameterName) {
}
}
Compile with javac -g TestClass.java
and then disassemble with javap -v TestClass
, the output is as follows:
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"
Why is LocalVariableTable
not included in the class file of the interface?
JDK version: 1.8.0_311
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为这不是类文件结构的工作原理。
根据 JVM 规范,
LocalVariableTable
是Code
属性的一部分:但是,接口方法是抽象的(即具有标志
ACC_ABSTRACT
),因此它们首先不能具有Code
属性(§4.7.3)。因此,
javac
不可能为您的抽象接口方法生成LocalVariableTable
,即使它愿意,因为这不会生成正确的类文件。另一种思考方式是,在具体实现该方法之前,该方法的参数实际上并不“存在”。毕竟,抽象方法应该只是一个“需求”而没有“实现”。我真的不明白为什么你会期望有局部变量,因为它们是实现细节。
Because that's not how the class file structure works.
According to the JVM spec, the
LocalVariableTable
is part of aCode
attribute:However, interface methods are abstract (i.e. having the flag
ACC_ABSTRACT
), so they can't haveCode
attributes in the first place (§4.7.3).So it is not possible for
javac
to generate aLocalVariableTable
for you abstract interface method, even if it wanted to, because that would not produce a correct class file.Another way to think about it is that the parameter of the method doesn't actually "exist" until you concretely implement it. After all, an abstract method is supposed to just be a "requirement" without "implementations". I don't really see why you would expect there to be local variables, since they are implementation details.
LocalVariableTable 描述了变量的范围——可以访问变量的字节码部分。
在类中,非抽象方法的参数有一个范围 - 它可以在整个方法体中访问。即使该方法为“空”,字节码仍然由单个
return
命令组成。(实例方法中还有隐式
this
变量,该变量也可以在方法的整个主体中访问)。在抽象接口方法(即不是默认方法或静态方法)中,没有可以访问该变量的字节码,因为该方法没有主体,因此没有字节码。因此,不需要
LocalVariableTable
。抽象方法(无论是在接口还是类中)只是一个规范,它表示“实现者需要提供这个”。没有实施,没有主体等。
The
LocalVariableTable
describes the scope of the variable - the portion of the bytecode in which the variable is accessible.In a class, the parameter of a non-abstract method has a scope - it's accessible in the whole of the body of the method. Even when the method is "empty", the bytecode still consists of a single
return
command.(There's also the implicit
this
variable in an instance method, which is also accessible in the whole body of the method).In an abstract interface method (i.e. not a
default
orstatic
method), there's no bytecode in which that variable is accessible, because the method has no body, and thus no bytecode. Hence, there's no need for theLocalVariableTable
.An abstract method (whether in an interface or a class) is just a specification which says "implementors need to provide this". There is no implementation, no body etc.