JVM动态链接的举例说明

  • Post author:
  • Post category:其他



全篇链接

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文件的常量池里。 比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么

    动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。



版权声明:本文为weixin_42383680原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。