java文件程序设计分析,深入浅析Java中 class文件的数据类型

深入浅析Java中 class文件的数据类型

发布时间:2020-11-23 17:39:45

来源:亿速云

阅读:103

作者:Leah

深入浅析Java中 class文件的数据类型?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

CONSTANT_Integer_info

一个常量池中的CONSTANT_Integer_info数据项, 可以看做是CONSTANT_Integer类型的一个实例。 它存储的是源文件中出现的int型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为3, 也就是说, 当虚拟机读到一个tag值为3的数据项时, 就知道这个数据项是一个CONSTANT_Integer_info, 它存储的是int型数值的值。 紧挨着tag的下面4个字节叫做bytes, 就是int型数值的整型值。 它的内存布局如下:

9601bed41086a1bdda1b75a07b929aa8.png

下面以示例代码进行说明, 示例代码如下:

package com.bjpowernode.test;

public class TestInt {

void printInt(){

System.out.println(65535);

}

}

将上面的类生成的class文件反编译:

1.D:\Workspace\AndroidWorkspace\BlogTest\bin>javap -v -c -classpath . com.bjpowernode.test.TestInt

下面列出反编译的结果, 由于反编译结果较长, 我们省略了大部分信息:

..................

..................

Constant pool:

..................

..................

#21 = Integer 65535

..................

..................

{

..................

..................

void printInt();

flags:

Code:

stack=2, locals=1, args_size=1

0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #21 // int 65535

5: invokevirtual #22 // Method java/io/PrintStream.println:(I)V

8: return

LineNumberTable:

line 6: 0

line 7: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 this Lcom/bjpowernode/test/TestInt;

}

上面的输出结果中, 保留了printInt方法的反编译结果, 并且保留了常量池中的第21项。 首先看printInt方法反编译结果中的索引为3 的字节码指令:

1.3: ldc           #21                 // int 65535

这条ldc指令, 引用了常量池中的第21项, 而第21项是一个CONSTANT_Integer_info, 并且这个CONSTANT_Integer_info存储的整型值为65535 。

CONSTANT_Float_info

一个常量池中的CONSTANT_Float_info数据项, 可以看做是CONSTANT_Float类型的一个实例。 它存储的是源文件中出现的float型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为4, 也就是说, 当虚拟机读到一个tag值为4的数据项时, 就知道这个数据项是一个CONSTANT_Float_info, 并且知道它存储的是float型数值。 紧挨着tag的下面4个字节叫做bytes, 就是float型的数值。 它的内存布局如下:

331766daaa7cbfa6a4d5ee6c1cd76238.png

举例说明, 如果源文件中的一句代码使用了一个float值, 如下所示:

void printFloat(){

System.out.println(1234.5f);

}

那么在这个类的常量池中就会有一个CONSTANT_Float_info与之相对应, 这个CONSTANT_Float_info的形式如下:

ed70496dccbc094710a94b07dea30b10.png

代码反编译结果如下:

Constant pool:

............

............

#29 = Float 1234.5f

...........

...........

{

............

............

void printFloat();

flags:

Code:

stack=2, locals=1, args_size=1

0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #29 // float 1234.5f

5: invokevirtual #30 // Method java/io/PrintStream.println:(F)V

8: return

LineNumberTable:

line 10: 0

line 11: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 this Lcom/bjpowernode/test/TestInt;

}

CONSTANT_Long_info

一个常量池中的CONSTANT_Long_info数据项, 可以看做是CONSTANT_Long类型的一个实例。 它存储的是源文件中出现的long型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为5, 也就是说, 当虚拟机读到一个tag值为5的数据项时, 就知道这个数据项是一个CONSTANT_Long_info, 并且知道它存储的是long型数值。 紧挨着tag的下面8个字节叫做bytes, 就是long型的数值。 它的内存布局如下:

af69ea76c1c8089520b7c3632b5efb9d.png

举例说明, 如果源文件中的一句代码使用了一个long型的数值, 如下所示:

void printLong(){

System.out.println(123456L);

}

那么在这个类的常量池中就会有一个CONSTANT_Long_info与之相对应, 这个CONSTANT_Long_info的形式如下:

e682131b635a9e73529ed8b2a404e422.png

代码反编译结果为:

Constant pool:

.............

.............

#21 = Long 123456l

.............

.............

{

..............

..............

void printLong();

flags:

Code:

stack=3, locals=1, args_size=1

0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc2_w #21 // long 123456l

6: invokevirtual #23 // Method java/io/PrintStream.println:(J)V

9: return

LineNumberTable:

line 7: 0

line 8: 9

LocalVariableTable:

Start Length Slot Name Signature

0 10 0 this Lcom/bjpowernode/test/TestInt;

}

CONSTANT_Double_info

一个常量池中的CONSTANT_Double_info数据项, 可以看做是CONSTANT_Double类型的一个实例。 它存储的是源文件中出现的double型数据的值。 同样, 作为常量池中的一种数据类型, 它的第一个字节也是一个tag值, 它的tag值为6, 也就是说, 当虚拟机读到一个tag值为6的数据项时, 就知道这个数据项是一个CONSTANT_Double_info, 并且知道它存储的是double型数值。 紧挨着tag的下面8个字节叫做bytes, 就是double型的数值。 它的内存布局如下:

2c57848b6d5615cc77b99292936bbc32.png

举例说明, 如果源文件中的一句代码使用了一个double型的数值, 如下所示:

void printDouble(){

System.out.println(123456D);

}

那么在这个类的常量池中就会有一个CONSTANT_Double_info与之相对应, 这个CONSTANT_Double_info的形式如下:

0e2f17e1ee371e67a9c1648f4e09ddb6.png

代码反编译结果为:

Constant pool:

............

............

#21 = Double 123456.0d

............

............

{

.............

.............

void printDouble();

flags:

Code:

stack=3, locals=1, args_size=1

0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc2_w #21 // double 123456.0d

6: invokevirtual #23 // Method java/io/PrintStream.println:(D)V

9: return

LineNumberTable:

line 7: 0

line 8: 9

LocalVariableTable:

Start Length Slot Name Signature

0 10 0 this Lcom/bjpowernode/test/TestInt;

}

CONSTANT_String_info

在常量池中, 一个CONSTANT_String_info数据项, 是CONSTANT_String类型的一个实例。 它的作用是存储文字字符串, 可以把他看做是一个存在于class文件中的字符串对象。 同样, 它的第一个字节是tag值, 值为8 , 也就是说, 虚拟机访问一个数据项时, 判断tag值为8 , 就说明访问的数据项是一个CONSTANT_String_info 。 紧挨着tag的后两个字节是一个叫做string_index的常量池引用, 它指向一个CONSTANT_Utf8_info, 这个CONSTANT_Utf8_info存放的才是字符串的字面量。 它的内存布局如下:

e90694181f5debb301406f2412cbb53a.png

举例说明, 如果源文件中的一句代码使用了一个字符串常量, 如下所示:

void printStrng(){

System.out.println("abcdef");

}

那么在这个类的常量池中就会有一个CONSTANT_String_info与之相对应, 反编译结果如下:

Constant pool:

............

............

#21 = String #22 // abcdef

#22 = Utf8 abcdef

............

.............

{

.............

.............

void printStrng();

flags:

Code:

stack=2, locals=1, args_size=1

0: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;

3: ldc #21 // String abcdef

5: invokevirtual #23 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

8: return

LineNumberTable:

line 7: 0

line 8: 8

LocalVariableTable:

Start Length Slot Name Signature

0 9 0 this Lcom/bjpowernode/test/TestInt;

}

其中printString方法中索引为3的字节码指令ldc引用常量池中的第21项, 第21项是一个CONSTANT_String_info, 这个位于第21项的CONSTANT_String_info又引用了常量池的第22项, 第22项是一个CONSTANT_Utf8_info, 这个CONSTANT_Utf8_info中存储的字符串是 abcdef 。 引用关系的内存布局如下:

69789cbd294297020d947ab1656570ad.png

总结

最后总结一下, 本文主要讲解了常量池中的五中数据项, 分别为CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info, CONSTANT_Double_info 和CONSTANT_String_info 。 这几种常量池数据项都是直接存储的常量值,而不是符号引用。 这里又一次出现了符号引用的概念, 这个概念将会在下一篇博客中详细讲解, 因为下一篇博客要介绍的剩下的四种常量池数据项, 都是符号引用, 这四种表示符号引用的数据项又会直接或间接引用上篇文章中介绍的CONSTANT_NameAndType_info和CONSTANT_Utf8_info, 所以说CONSTANT_NameAndType_info是符号引用的一部分。

看完上述内容,你们掌握深入浅析Java中 class文件的数据类型的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java,有两种内部类:静态内部类和非静态内部类。它们的主要区别在于访问方式和用途。 静态内部类是一个独立的类,但它是作为宿主类的一个静态成员存在的。它可以访问宿主类的静态成员,但不能直接访问宿主类的非静态成员。另外,静态内部类的实例化不依赖于宿主类的实例化,可以直接通过宿主类访问或使用。静态内部类通常用于将一个类嵌套在另一个类,并与其它外部类共享。 非静态内部类是一个依赖于宿主类实例的类,它只能在宿主类的实例被实例化。非静态内部类可以直接访问宿主类的成员,包括静态和非静态成员。非静态内部类的实例化必须依赖于宿主类的实例,并通过宿主类的实例访问或使用。非静态内部类通常用于充当宿主类的辅助类,以提供更多特定于宿主类实例的功能。 总结起来,静态内部类可以看作是宿主类的静态成员,独立于宿主类的实例存在,并且可以直接使用宿主类的静态成员;非静态内部类是宿主类的一部分,依赖于宿主类的实例存在,并且可以直接使用宿主类的所有成员。 在实际应用,选择使用静态内部类还是非静态内部类取决于具体需求。如果一个类不依赖于宿主类的实例,且能够独立使用,那么可以使用静态内部类;如果一个类需要依赖于宿主类的实例,并且需要访问宿主类的成员,那么就需要使用非静态内部类。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值