当我看到JVM规范时,它说每个类最多具有一个类初始化方法,即“ clinit”,因此我认为我们应该有一些命令来查看此方法在.class文件中的编码方式。
起初我以为使用javap可以,但是我发现它没有用。
最佳答案
javap
命令显示<init>
和<clinit>
方法...尽管它不使用这些名称。 (请参见下面的public Test();
和static {};
“方法”。)
或者,您也可以使用其他反汇编程序。例如,Krakatau将在其输出中显示内部名称"<init>"
和"<clinit>"
。
我一直认为<clinit>
文件中有一个方法名称.class
。
你是对的。这些名称将出现在方法的.class
文件表示中。并且您可以在<init>
打印的常量表中看到内部方法名称<clinit>
和javap
。
只是javap
的实现者选择了不在方法部分中显示那些方法名称。他们使用了不同的表示法。
(为什么?我的猜测是,他们认为如果这样做的话,大多数人会更容易理解javap输出!对吗?我不知道,但是无论如何这都是没有意义的。)
$ cat Test.java
public class Test {
static String foo = "hello";
}
$ javap -p -c -s -v Test
Classfile /tmp/Test.class
Last modified Feb 23, 2019; size 293 bytes
MD5 checksum 724ea13308a150d0cc5730edcf4db616
Compiled from "Test.java"
public class Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #5.#15 // java/lang/Object."<init>":()V
#2 = String #16 // hello
#3 = Fieldref #4.#17 // Test.foo:Ljava/lang/String;
#4 = Class #18 // Test
#5 = Class #19 // java/lang/Object
#6 = Utf8 foo
#7 = Utf8 Ljava/lang/String;
#8 = Utf8 <init>
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 <clinit>
#13 = Utf8 SourceFile
#14 = Utf8 Test.java
#15 = NameAndType #8:#9 // "<init>":()V
#16 = Utf8 hello
#17 = NameAndType #6:#7 // foo:Ljava/lang/String;
#18 = Utf8 Test
#19 = Utf8 java/lang/Object
{
static java.lang.String foo;
descriptor: Ljava/lang/String;
flags: ACC_STATIC
public Test();
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
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: ldc #2 // String hello
2: putstatic #3 // Field foo:Ljava/lang/String;
5: return
LineNumberTable:
line 2: 0
}
SourceFile: "Test.java"