前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个求水仙花数的类的字节码分析

一个求水仙花数的类的字节码分析

作者头像
冬天里的懒猫
发布2021-08-10 10:45:02
2590
发布2021-08-10 10:45:02
举报

1.源码

代码如下:

代码语言:javascript
复制
package com.dhb.geektimestudy.kimmking.week1;

public class Hello {

	private static final int min = 100;
	private static final int max = 1000;
	
	public static void main(String[] args) {
		Hello.findLotus();
	}
	
	public void findLotus() {
		
		for(int i=min;i<max;i++) {
			int first = i/100;
			int second = i/10%10;
			int third = i%10;
			if(first*first*first + second*second*second + third*third*third == i) {
				System.out.println(i);
			}
		}
	}
}

2.字节码

使用javap得到字节码: javap -verbose com.dhb.geektimestudy.kimmking.week1.Hello

代码语言:javascript
复制
Classfile /D:/workspace-mashibing/geektime-study/build/classes/java/main/com/dhb/geektimestudy/kimmking/week1/Hello.class
  Last modified 2021-8-5; size 917 bytes
  MD5 checksum 57013feb11612a9db90c9b078976db4f
  Compiled from "Hello.java"
public class com.dhb.geektimestudy.kimmking.week1.Hello
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#33         // java/lang/Object."<init>":()V
   #2 = Methodref          #3.#34         // com/dhb/geektimestudy/kimmking/week1/Hello.findLotus:()V
   #3 = Class              #35            // com/dhb/geektimestudy/kimmking/week1/Hello
   #4 = Fieldref           #36.#37        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Methodref          #38.#39        // java/io/PrintStream.println:(I)V
   #6 = Class              #40            // java/lang/Object
   #7 = Utf8               min
   #8 = Utf8               I
   #9 = Utf8               ConstantValue
  #10 = Integer            100
  #11 = Utf8               max
  #12 = Integer            1000
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               LocalVariableTable
  #18 = Utf8               this
  #19 = Utf8               Lcom/dhb/geektimestudy/kimmking/week1/Hello;
  #20 = Utf8               main
  #21 = Utf8               ([Ljava/lang/String;)V
  #22 = Utf8               args
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               MethodParameters
  #25 = Utf8               findLotus
  #26 = Utf8               first
  #27 = Utf8               second
  #28 = Utf8               third
  #29 = Utf8               i
  #30 = Utf8               StackMapTable
  #31 = Utf8               SourceFile
  #32 = Utf8               Hello.java
  #33 = NameAndType        #13:#14        // "<init>":()V
  #34 = NameAndType        #25:#14        // findLotus:()V
  #35 = Utf8               com/dhb/geektimestudy/kimmking/week1/Hello
  #36 = Class              #41            // java/lang/System
  #37 = NameAndType        #42:#43        // out:Ljava/io/PrintStream;
  #38 = Class              #44            // java/io/PrintStream
  #39 = NameAndType        #45:#46        // println:(I)V
  #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               (I)V
{
  public com.dhb.geektimestudy.kimmking.week1.Hello();
    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 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/dhb/geektimestudy/kimmking/week1/Hello;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #2                  // Method findLotus:()V
         3: return
      LineNumberTable:
        line 9: 0
        line 10: 3
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args

  public static void findLotus();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=4, args_size=0
         0: bipush        100
         2: istore_0
         3: iload_0
         4: sipush        1000
         7: if_icmpge     62
        10: iload_0
        11: bipush        100
        13: idiv
        14: istore_1
        15: iload_0
        16: bipush        10
        18: idiv
        19: bipush        10
        21: irem
        22: istore_2
        23: iload_0
        24: bipush        10
        26: irem
        27: istore_3
        28: iload_1
        29: iload_1
        30: imul
        31: iload_1
        32: imul
        33: iload_2
        34: iload_2
        35: imul
        36: iload_2
        37: imul
        38: iadd
        39: iload_3
        40: iload_3
        41: imul
        42: iload_3
        43: imul
        44: iadd
        45: iload_0
        46: if_icmpne     56
        49: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        52: iload_0
        53: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
        56: iinc          0, 1
        59: goto          3
        62: return
      LineNumberTable:
        line 14: 0
        line 15: 10
        line 16: 15
        line 17: 23
        line 18: 28
        line 19: 49
        line 14: 56
        line 22: 62
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           15      41     1 first   I
           23      33     2 second   I
           28      28     3 third   I
            3      59     0     i   I
      StackMapTable: number_of_entries = 3
        frame_type = 252 /* append */
          offset_delta = 3
          locals = [ int ]
        frame_type = 52 /* same */
        frame_type = 250 /* chop */
          offset_delta = 5
}
SourceFile: "Hello.java"

3.字节码分析

3.1 常量池及类属性部分

版本号:

代码语言:javascript
复制
  minor version: 0  //次版本号 0000
  major version: 52 //主版本号 1.8
  flags: ACC_PUBLIC, ACC_SUPER //类访问标识 public
//常量池内容 从#1开始,#0的常量池有特殊作用
Constant pool:
   #1 = Methodref          #6.#33         // java/lang/Object."<init>":()V
   #2 = Methodref          #3.#34         // com/dhb/geektimestudy/kimmking/week1/Hello.findLotus:()V
   #3 = Class              #35            // com/dhb/geektimestudy/kimmking/week1/Hello
   #4 = Fieldref           #36.#37        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Methodref          #38.#39        // java/io/PrintStream.println:(I)V
   #6 = Class              #40            // java/lang/Object
   #7 = Utf8               min
   #8 = Utf8               I
   #9 = Utf8               ConstantValue
  #10 = Integer            100
  #11 = Utf8               max
  #12 = Integer            1000
  #13 = Utf8               <init>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Utf8               LineNumberTable
  #17 = Utf8               LocalVariableTable
  #18 = Utf8               this
  #19 = Utf8               Lcom/dhb/geektimestudy/kimmking/week1/Hello;
  #20 = Utf8               main
  #21 = Utf8               ([Ljava/lang/String;)V
  #22 = Utf8               args
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               MethodParameters
  #25 = Utf8               findLotus
  #26 = Utf8               first
  #27 = Utf8               second
  #28 = Utf8               third
  #29 = Utf8               i
  #30 = Utf8               StackMapTable
  #31 = Utf8               SourceFile
  #32 = Utf8               Hello.java
  #33 = NameAndType        #13:#14        // "<init>":()V
  #34 = NameAndType        #25:#14        // findLotus:()V
  #35 = Utf8               com/dhb/geektimestudy/kimmking/week1/Hello
  #36 = Class              #41            // java/lang/System
  #37 = NameAndType        #42:#43        // out:Ljava/io/PrintStream;
  #38 = Class              #44            // java/io/PrintStream
  #39 = NameAndType        #45:#46        // println:(I)V
  #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               (I)V

3.2 findLotus() 方法

代码语言:javascript
复制
 descriptor: ()V  //主要描述方法的参数和返回值进行描述,改方法没有参数和返回值,因此为()V
 flags: ACC_PUBLIC, ACC_STATIC   //访问标识,说明该方法时 public static修饰
  Code:
      stack=3, locals=4, args_size=0  //stack深度为3,本地变量为4 由于方法没有输入参数,因此args_size=0

关于code中 指令部分,用下表来分析

指令

程序计数器

局部变量表

stack

说明

0: bipush 100

0

< >< >< >< >

100

将100压入stack顶

2: istore_0

2

<100><><><>

将stack顶部的100写入局部变量表中index为0的位置

3: iload_0

3

<100>< >< >< >

100

将局部变量表#0的数据load到stack顶

4: sipush 1000

4

<100>< >< >< >

1000->100

将1000压入stack顶部

7: if_icmpge 62

7

<100>< >< >< >

1000->100

判断stack中的两个数据,栈底数据100是否大于等于栈顶1000,如果满足则跳转到程序计数器为62的指令

10: iload_0

10

<100>< >< >< >

100

将局部变量表中#0load到stack顶部

11: bipush 100

11

<100>< >< >< >

100->100

将100压入stack顶部

13: idiv

13

<100>< >< >< >

1

将stack底部的数据除以stack顶部的数据,得到的结果存在stack顶部

14: istore_1

14

<100><1>< >< >

将stack顶部的数据写入到局部变量表的#1位置

15: iload_0

15

<100><1 >< >< >

100

将局部变量表中#0load到stack顶部

16: bipush 10

16

<100><1>< >< >

10->100

将10压入stack顶部

18: idiv

18

<100><1 >< >< >

10

将stack底部的数据100除以stack顶部的数据10,得到的结果10存在stack顶部

19: bipush 10

19

<100><1>< >< >

10->10

将10压入stack顶部

21: irem

20

<100><1 >< >< >

0

将stack底部的数据10与stack顶部的数据10取余,得到的结果0存在stack顶部

22: istore_2

22

<100><1><0>< >

将stack顶部数据0存入局部变量表的#2位置

23: iload_0

23

<100><1><0>< >

100

将局部变量表#0的数据load到stack顶

24: bipush 10

24

<100><1><0>< >

10->100

将10压入stack顶部

26: irem

26

<100><1><0>< >

0

将stack底部的数据10与stack顶部的数据10取余,得到的结果0存在stack顶部

27: istore_3

27

<100><1><0><0>

将stack顶部数据0存入局部变量表的#3位置

28: iload_1

28

<100><1><0><0>

1

将局部变量表#1的数据load到stack顶

29: iload_1

29

<100><1><0><0>

1->1

将局部变量表#1的数据再次load到stack顶

30: imul

30

<100><1><0><0>

1

将stack底部的数据1与stack顶部的数据1求积,得到的结果1存在stack顶部

31: iload_1

31

<100><1><0><0>

1->1

将局部变量表#1的数据load到stack顶

32: imul

32

<100><1><0><0>

1

stack底部的数据1与stack顶部的数据1求积,得到的结果1存在stack顶部

33: iload_2

33

<100><1><0><0>

0-> 1

将局部变量表#2的数据load到stack顶

34: iload_2

34

<100><1><0><0>

0->0->1

将局部变量表#2的数据load到stack顶

35: imul

35

<100><1><0><0>

0->1

将stack顶部的两个数据0,0求积,其结果0存在stack顶部

36: iload_2

36

<100><1><0><0>

0->0->1

将局部变量表#2的数据load到stack顶

37: imul

37

<100><1><0><0>

0->1

将stack顶部的两个数据0,0求积,其结果0存在stack顶部

38: iadd

38

<100><1><0><0>

1

将stack顶部两个数据0,1求和,其结果存在stack顶部

39: iload_3

39

<100><1><0><0>

0->1

将局部变量表#3的数据load到stack顶

40: iload_3

40

<100><1><0><0>

0->0->1

将局部变量表#3的数据再次load到stack顶

41: imul

41

<100><1><0><0>

0->1

将stack顶部两个数据0,0求积,其结果0存在stack顶部

42: iload_3

42

<100><1><0><0>

0->0->1

将局部变量表#3的数据load到stack顶

43: imul

43

<100><1><0><0>

0->1

将stack顶部两个数据0,0求积,其结果0存在stack顶部

44: iadd

44

<100><1><0><0>

1

将stack顶部两个数据0,1求和,其结果1存在stack顶部

45: iload_0

45

<100><1><0><0>

100->1

将局部变量表#0的数据load到stack顶

46: if_icmpne 56

56

<100><1><0><0>

比较stack顶部两个数据是否相等,如果不等则跳转到56对应的字节码的指令,此出不等,则会发生跳转

49: getstatic #4

49

<100><1><0><0>

调用静态方法,方法名为常量池的#4位置,即 java/lang/System.out:Ljava/io/PrintStream;

52: iload_0

52

<100><1><0><0>

局部变量表#0所在的值

将局部变量表#0load

53: invokevirtual #5

53

<100><1><0><0>

局部变量表#0所在的值

调用实例方法,方法名在常量池的#5,即java/io/PrintStream.println:(I)V

56: iinc 0, 1

56

<101><1><0><0>

将局部变量表#0的变量增加1 ,变成了101

59: goto 3

3

<101><1><0><0>

跳转到3对应的字节码

62: return

62

< >< >< >< >

无返回值,方法结束

上表中即是方法findLotus的核心计算过程的字节码及对应的程序计数器、局部变量表、stack的执行全过程。 上述过程中只对所有指令做了一次描述,对于goto之后的过程都省略了。实际上执行的过程则会根据执行的if判断和goto进行跳转。 剩余部分字节码:

代码语言:javascript
复制
//行号表
 LineNumberTable:
        line 14: 0
        line 15: 10
        line 16: 15
        line 17: 23
        line 18: 28
        line 19: 49
        line 14: 56
        line 22: 62
 //方法的局部变量描述,也就是代码中定义的局部变量名
 LocalVariableTable:
        Start  Length  Slot  Name   Signature
           15      41     1 first   I
           23      33     2 second   I
           28      28     3 third   I
            3      59     0     i   I
 //stack图的属性 为了提高JVM在类型检查的验证过程的效率
      StackMapTable: number_of_entries = 3
        frame_type = 252 /* append */
          offset_delta = 3
          locals = [ int ]
        frame_type = 52 /* same */
        frame_type = 250 /* chop */
          offset_delta = 5

3.3 构造函数

在生成的字节码中,可以看到生成了Hello默认的无参构造函数。

代码语言:javascript
复制
  public com.dhb.geektimestudy.kimmking.week1.Hello();
    //无输入参数和返回值
    descriptor: ()V
    //访问标识 public
    flags: ACC_PUBLIC
    Code:
      //stack深度1,局部变量1,args为1
      stack=1, locals=1, args_size=1
         //将局部变量load到stack
         0: aload_0
         //调用Object的init方法
         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/dhb/geektimestudy/kimmking/week1/Hello;

3.4 main方法

代码语言:javascript
复制
  public static void main(java.lang.String[]);
    //main输入参数 string数组
    descriptor: ([Ljava/lang/String;)V
    //访问标识 public static
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      //stack深度为0 局部变量1 
      stack=0, locals=1, args_size=1
         //调用 findLotus 方法
         0: invokestatic  #2                  // Method findLotus:()V
         3: return
      //行号表
      LineNumberTable:
        line 9: 0
        line 10: 3
      //局部变量表
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;
    MethodParameters:
      Name                           Flags
      args
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.源码
  • 2.字节码
  • 3.字节码分析
    • 3.1 常量池及类属性部分
      • 3.2 findLotus() 方法
        • 3.3 构造函数
          • 3.4 main方法
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档