当前位置: 首页 > 知识库问答 >
问题:

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

缑永年
2023-03-14

当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-gtestclass编译。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

共有2个答案

万涵亮
2023-03-14

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

根据JVM规范,LocalAnalyableTableCode属性的一部分:

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

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

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

如果方法是本机抽象,并且不是类或接口初始化方法,则其method_info结构在其属性表中不得具有Code属性。

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

贺高杰
2023-03-14

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

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

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

在接口中,没有可访问该变量的字节码,因为该方法没有主体,因此没有字节码。因此,不需要LocalVariableTable

接口只是一个说明“实现者需要提供这个”。没有执行,没有机构等等。

 类似资料:
  • 问题内容: 您好,我有3个Java文件 我设法使用生成了A和B的.class文件 但是当我对c.java执行相同操作时,出现错误错误:找不到符号b和c 关于如何解决此问题的任何建议? 所有的Java文件都在同一个文件夹中 问题答案: 尝试编译class时,必须具有类并且在类路径中。这使编译器可以验证它们是否存在,找出它们具有哪些方法等。 对包名称和类路径非常敏感。最简单的方法是像这样同时编译这三个

  • 问题内容: 我想知道为什么我们通过编译显示“ Hello,World!”的.c文件得到.o文件。是否大于Java .class文件,该文件也显示“ Hello,World!”? 问题答案: Java使用字节码来独立于平台并进行“预编译”,但是字节码由解释器使用并且被提供为足够紧凑,因此您在已编译的C程序中看到的机器代码并不相同。只需看一下Java编译的完整过程即可: 这是Java程序到机器代码转换

  • 问题内容: 在Java has 方法中,但是,它仅在诸如或的关联容器中使用。为什么要这样设计?具有方法的界面看起来更优雅。 问题答案: 在我看来,主要的论据是,可以为任何Java对象计算出一个定义明确的默认值,以及一个同样定义明确的。根本没有充分的理由要保留所有对象的该功能,当然也有很多理由 不 保留此功能。因此,这本书毫无疑问。

  • 我使用IntelliJ进行java开发。我想在我只有shell访问权限的另一台主机上运行我的应用程序。 当我在本地运行应用程序时,一切都很好。当我尝试在远程主机上编译代码时,我得到: 文件位于同一目录中: 我也不能在本地编译,除非它来自IDE,所以我假设我只是没有做正确的事情。我错过了什么?我只想能够从shell运行我的应用程序,我真的不在乎如何运行。

  • 问题内容: 我意识到字节码与本机代码(可移植性)的好处。 但是要说您始终知道您的代码将在x86架构上运行,为什么不为x86编译并获得性能收益呢? 请注意,我假设本机代码编译会提高性能。有些人回答说,实际上没有任何收获对我来说是个新闻。 问题答案: 因为性能提升(如果有)是不值得的。 同样, 垃圾回收 对于性能也很重要。很有可能JVM的GC优于嵌入在已编译的可执行文件中的GC,例如使用GCJ。 而

  • 问题内容: 我的文件夹中有四个Java文件。它们都在同一包中。这是包裹声明 所有这些类都在同一包中。我想知道如何使用它们来编译它们(我是说我不知道​​如何编译正在使用的多个文件)。一旦完成,如何启动然后在CLI中使用命令?这是文件名。 问题答案: 从项目的根目录: 要运行,假设没有其他依赖项: (假设具有正常功能。) 该命令将编译软件包目录中的所有文件。由于它们都在同一个包/目录中,因此可以使用。