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

Why is there no LocalVariableTable in the class file compiled with javac -g for the Java interface?

当Java文件为接口时,如TestInterface.java:

public interface TestInterface {

    void method(String parameterName);

}

我用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"

而当Java文件为class时,如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没有包含在接口的class文件中?

JDK版本:1.8.0_311

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

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

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

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

抽象方法(无论是在接口中还是在 class 中)只是一个说明“实现者需要提供这个”的规范。没有实现,没有正文等

因为那不是 class 文件结构的工作方式。

根据 JVM specLocalVariableTableCode 属性的一部分:

The LocalVariableTable attribute is an optional variable-length attribute in the attributes table of a Code attribute (§4.7.3). It may be used by debuggers to determine the value of a given local variable during the execution of a method.

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

The Code attribute is a variable-length attribute in the attributes table of a method_info structure (§4.6). A Code attribute contains the Java Virtual Machine instructions and auxiliary information for a method [...]

If the method is either native or abstract, and is not a class or interface initialization method, then its method_info structure must not have a Code attribute in its attributes table.

因此 javac 不可能为您生成一个 LocalVariableTable 抽象接口方法,即使它想要,因为那样不会生成正确的 class 文件。

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