当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文件是一个类时,比如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ķ

推荐答案

因为类文件 struct 不是这样工作的.

根据JVM specLocalVariableTableCode属性的一部分:

Code属性的attributes表中,LocalVariableTable属性是可选的可变长度属性(§4.7.3).调试器可以在方法执行期间使用它来确定给定局部变量的值.

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

Code属性是method_info struct 的attributes表中的可变长度属性(§4.6).Code属性包含Java虚拟机指令和方法[…]的辅助信息

如果该方法是nativeabstract,并且不是类或接口初始化方法,则其method_info struct 在其attributes表中不能有Code属性.

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

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

Java相关问答推荐

Java SSLocket查明客户端是否发送了证书

为什么JFrame paint()多次绘制同一点(或根本不绘制)?

将成为一个比较者.比较…在现代Java中,编译器会对`CompareTo`方法进行优化吗?

如何在访问完所有文件后加入所有线程?

为什么在枚举中分支预测比函数调用快?

Com.example.service.QuestionService中的构造函数的参数0需要找不到的类型为';com.example.Dao.QuestionDao;的Bean

如何获取Instant#of EpochSecond(?)的最大值

如何使用Jackson将XML元素与值和属性一起封装

如何让JVM在SIGSEGV崩溃后快速退出?

我的Spring Boot测试显示&IlLegalStateException:无法加载某事的ApplicationContext.

在添加AdMob时无法为Google Play构建应用程序包:JVM垃圾收集器崩溃和JVM内存耗尽

通过Java列表中的某些字段搜索值

寻找Thread.sky()方法的清晰度

Java.time.OffsetDateTime的SQL Server数据库列类型是什么?

Java中的发布/订阅-Long Live和Short Live Publisher,哪种方法是正确的?

在WHILE()循环初始化部分中声明和初始化变量的Java语法?

在Spring Boot中使用咖啡因进行缓存

Spring Boot Security-每个端点都被403禁止,Spring记录一个BasicErrorController#错误(HttpServlet请求)

获取月份';s在java中非UTC时区的开始时间和结束时间

将天数添加到ZonedDateTime不会更改时间