当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
因为类文件结构不是这样工作的。
根据JVM规范,LocalAnalyableTable
是Code
属性的一部分:
LocalVariableTable
属性是code
属性(§4.7.3)的attributes
表中的可选可变长度属性。调试器可以在方法执行期间使用它来确定给定局部变量的值。
然而,接口方法是抽象的(即具有标志ACC_ABSTRACT
),因此它们不能首先具有Code
属性(§4.7.3)。
code
属性是method_info
结构(§4.6)的attributes
表中的可变长度属性。code
属性包含方法[…]的Java虚拟机指令和辅助信息
如果方法是本机
或抽象
,并且不是类或接口初始化方法,则其method_info
结构在其属性
表中不得具有Code
属性。
另一种思考方法是,在具体实现该方法之前,该方法的参数实际上并不“存在”。毕竟,抽象方法应该只是“需求”,而不是“实现”。我真的不明白为什么会有局部变量,因为它们是实现细节。
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中使用命令?这是文件名。 问题答案: 从项目的根目录: 要运行,假设没有其他依赖项: (假设具有正常功能。) 该命令将编译软件包目录中的所有文件。由于它们都在同一个包/目录中,因此可以使用。