java代码
package com.company;
public class Main {
static int num = 10;
public static void main(String[] args) {
methodA();
}
public static void methodA(){
System.out.println("methodA().....");
methodB();
}
public static void methodB(){
System.out.println("methodB()....");
}
}
对应.class代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.company;
public class Main {
static int num = 10;
public Main() {
}
public static void main(String[] args) {
methodA();
}
public static void methodA() {
System.out.println("methodA().....");
methodB();
}
public static void methodB() {
System.out.println("methodB()....");
}
}
对应的‘反编译’
javap -v Main.class
Compiled from “Main.java”
public class com.company.Main
minor version: 0
major version: 54
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #9 // com/company/Main
super_class: #10 // java/lang/Object
interfaces: 0, fields: 1, methods: 5, attributes: 1
Constant pool:
#1 = Methodref #10.#29 去#10和#29寻找 // java/lang/Object.”<init>”:()V(构成器方法,无参)
#2 = Methodref #9.#30 // com/company/Main.methodA:()V
#3 = Fieldref
#31.#32
// java/lang/System.out:Ljava/io/PrintStream;
#4 = String #33 // methodA()…..
#5 = Methodref #34.#35 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Methodref #9.#36 // com/company/Main.methodB:()V
#7 = String #37 // methodB()….
#8 = Fieldref #9.#38 // com/company/Main.num:I
#9 = Class #39 // com/company/Main
#10 = Class #40 // java/lang/Object
#11 = Utf8 num
#12 = Utf8 I
#13 = Utf8 <init>
#14 = Utf8 ()V
#15 = Utf8 Code
#16 = Utf8 LineNumberTable
#17 = Utf8 LocalVariableTable
#18 = Utf8 this
#19 = Utf8 Lcom/company/Main;
#20 = Utf8 main
#21 = Utf8 ([Ljava/lang/String;)V
#22 = Utf8 args
#23 = Utf8 [Ljava/lang/String;
#24 = Utf8 methodA
#25 = Utf8 methodB
#26 = Utf8 <clinit>
#27 = Utf8 SourceFile
#28 = Utf8 Main.java
#29 = NameAndType #13:#14 // “<init>”:()V
#30 = NameAndType #24:#14 // methodA:()V
#31 = Class #41 // java/lang/System
#32 = NameAndType #42:#43 // out:Ljava/io/PrintStream;
#33 = Utf8 methodA()…..
#34 = Class #44 // java/io/PrintStream
#35 = NameAndType #45:#46 // println:(Ljava/lang/String;)V
#36 = NameAndType #25:#14 // methodB:()V
#37 = Utf8 methodB()….
#38 = NameAndType #11:#12 // num:I
#39 = Utf8 com/company/Main
#40 = Utf8 java/lang/Object
#41 = Utf8 java/lang/System
#42 = Utf8 out
#43 = Utf8 Ljava/io/PrintStream;
#44 = Utf8 java/io/PrintStream
#45 = Utf8 println
#46 = Utf8 (Ljava/lang/String;)V
{
static int num;
descriptor: I
flags: (0x0008) ACC_STATIC
public com.company.Main();
descriptor: ()V
flags: (0x0001) 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 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/company/Main;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method methodA:()V
3: return
LineNumberTable:
line 8: 0
line 9: 3
LocalVariableTable:
Start Length Slot Name Signature
0 4 0 args [Ljava/lang/String;
public static void methodA();
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: getstatic
#3
(向常量池中寻找)
// Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc
#4
// String methodA()…..
5: invokevirtual
#5
// Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: invokestatic
#6
// Method methodB:()V
11: return
LineNumberTable:
line 12: 0
line 13: 8
line 14: 11
public static void methodB();
descriptor: ()V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=0, args_size=0
0: getstatic
#3
// Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc
#7
// String methodB()….
5: invokevirtual
#5
// Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 17: 0
line 19: 8
static {};
descriptor: ()V
flags: (0x0008) ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 10
2: putstatic #8 // Field num:I
5: return
LineNumberTable:
line 5: 0
}
SourceFile: “Main.java”
3.动态链接(Dynamic Linking)(或指向运行时常量池的方法引用)
- 每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用。 包含这个引用的目的就是为了支持当前方法的代码能够实现动态链接( Dynamic Linking)。比如: invokedynamic指令
-
在Java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用( symbolic Reference)保存在class文件的常量池里。 比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么
动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。