为什么Java接口用javac -g编译的类文件中没有LocalVariableTable?

Poi*_*son 2 java javac java-8

当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

Swe*_*per 6

因为这不是类文件结构的工作原理。

\n

根据JVM 规范,它LocalVariableTable是属性的一部分Code

\n
\n

该属性是属性表(\xc2\xa74.7.3)LocalVariableTable中的可选可变长度属性。调试器可以使用它来确定方法执行期间给定局部变量的值。attributesCode

\n
\n

但是,接口方法是抽象的(即具有标志),因此它们首先ACC_ABSTRACT不能具有属性( \xc2\xa74.7.3)。Code

\n
\n

该属性是结构体表(\xc2\xa74.6)Code中的可变长度属性。属性包含 Java 虚拟机指令和方法的辅助信息 [...]attributesmethod_infoCode

\n

如果该方法是 或nativeabstract并且不是类或接口初始化方法,则其结构在其表中method_info不得有属性。Codeattributes

\n
\n

因此,即使它愿意,也不可能为您javac生成抽象接口方法,因为这不会生成正确的类文件。LocalVariableTable

\n

另一种思考方式是,在具体实现该方法之前,该方法的参数实际上并不“存在”。毕竟,抽象方法应该只是一个“需求”而没有“实现”。我真的不明白为什么你会期望有局部变量,因为它们是实现细节。

\n


And*_*ner 5

描述LocalVariableTable了变量的范围——可以访问变量的字节码部分。

在类中,非抽象方法的参数有一个范围 - 它可以在整个方法体中访问。即使该方法为“空”,字节码仍然由单个return命令组成。

(实例方法中还有隐式this变量,也可以在方法的整个主体中访问)。

在抽象接口方法(即不是defaultorstatic方法)中,没有可以访问该变量的字节码,因为该方法没有主体,因此没有字节码。因此,没有必要使用LocalVariableTable.

抽象方法(无论是在接口还是类中)只是一个规范,它表示“实现者需要提供这个”。没有实施,没有主体等。

  • *“接口只是一个规范,它说“实现者需要提供这个”。没有实现,没有主体等。”* - 在 Java 8+ 中,“接口”可以具有“默认”和“静态”方法有一个实现/主体/字节码。但当然,不是OP的例子。 (3认同)