博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
通过Java字节码发现有趣的内幕之String篇(上)(转)
阅读量:6174 次
发布时间:2019-06-21

本文共 1817 字,大约阅读时间需要 6 分钟。

原文出处: 

很多时候我们在编写Java代码时,判断和猜测代码问题时主要是通过运行结果来得到答案,本博文主要是想通过Java字节码的方式来进一步求证我们已知的东西。这里没有对Java字节码知识进行介绍,如果想了解更多的Java字节码或对其感兴趣的朋友可以先阅读。

String字面量可以通过’==’判断两个字符串是否相同,是因为大家都知道’==’是用来判断两个对象的值引用地址是否一致,两个值一样的字符串字面量定义是否指向同一个值内存地址呢?答案是肯定的。

1
2
3
4
5
6
7
8
9
10
package
com.jaffa.test.string;
 
public
class
ConstPoolTest {
    
public
static
void
main(String[] args){
        
String str1 =
"strVal_1"
;
        
String str2 =
"strVal_1"
;
        
//print str1==str2 is true
        
System.out.printf(
"str1==str2 is %b"
,str1==str2);
    
}
}

代码中声明了str1和str2的字面量值都为strVal_1,并且打印出str1==str2为true,说明两个str1和str2变量同时指向同一个字符串常量值的内存地址,下面通过Java字节码来验证这个结果。

在命令行我们通过javap工具来查看一个class文件的字节码。

1
javap -v com.jaffa.test.string.ConstPoolTest

在Constant pool列表中看到#16为一个String类型并值指向#17,而#17是一个utf8字符集编码值为strVal_1,所以#16和#17最终表达就是在常量池中有个String类型值为strVal_1的常量数据。

那接下来需要确认str1和str2两个变量值是否都是指向#16呢?

1
2
3
4
5
//ldc表示将一个常量加载到操作数栈
 
0
: ldc           #
16    
//将#16对应的常量值加载到操作数栈中           
 
2
: astore_1             
//将当前操作数栈中赋于变量1,即str1
 
3
: ldc           #
16    
//再次将#16对应的常量值加载到操作数栈中
 
5
: astore_2             
//将当前操作数栈中赋于变量2,即str2

从上面字节码执行来看,str1和str2都是被赋于同一个常量值,由此可以得出两个变更指向同一个内存地址。

通过同样的方式,我们来看一下如果是非字面量的情况会是怎么样的,Java代码如下:

1
2
3
4
5
6
7
8
9
10
package
com.jaffa.test.string;
 
public
class
ConstPoolTest {
    
public
static
void
main(String[] args){
        
String str1 =
"strVal_1"
;
        
String str2 =
new
String(
"strVal_1"
);
 
        
System.out.printf(
"str1==str2 is %b"
,str1==str2);
    
}
}

上面代码输出结果为false,通过javap查看发现str2变量的字节码指令发生了变化,如下现两截图:

1
2
3
4
5
6
7
8
//ldc表示将一个常量加载到操作数栈
 
0
: ldc           #
16    
//将#16对应的常量值加载到操作数栈中           
 
2
: astore_1             
//将当前操作数栈中赋于变量1,即str1
 
3
:
new          
#
18    
//创建了一个类实例,#18指向一个实例类型String
 
6
: dup                  
//配置上行完成操作栈指令
 
7
: ldc           #
16    
//将#16对应的常量值加载到操作数栈中
 
9
: invokespecial #
20    
//调用String实例初始化方法,并将#16输入
12
: astore_2             
//将new出来的实例赋于变量2,即str2

这时str2变量是创建一个新的内存地址,而非直接指向#16常量内存地址,所以str1==str2的结果为false。同时可以看到通过new String()带来看更多的字节码指令操作,运行上花费了更多的系统资源。

本系列:

 

http://www.importnew.com/18785.html

转载地址:http://dptba.baihongyu.com/

你可能感兴趣的文章
eclipse 构建maven web工程
查看>>
237. Delete Node in a Linked List
查看>>
[转] webpack之plugin内部运行机制
查看>>
宽字节与多字节之间的转换
查看>>
SEO的重要性
查看>>
ASP.NET 运行时详解 揭开请求过程神秘面纱
查看>>
Oracle 索引的失效检查
查看>>
C语言第五次作业--数据类型
查看>>
系统架构师-基础到企业应用架构-业务逻辑层
查看>>
高手详解SQL性能优化十条建议
查看>>
修改 IntelliJ IDEA 默认配置路径
查看>>
《现在的泪,都是当年脑子进的水》读书笔记
查看>>
IOSday04 UIButton使用
查看>>
铁大好青年内部分组
查看>>
unity3D ——自带寻路Navmesh入门教程(一)(转)
查看>>
判断字符串是否为数字的函数
查看>>
[emuch.net]MatrixComputations(7-12)
查看>>
linux 命令 — 文件相关
查看>>
自己空闲的时候封装一下
查看>>
Datagard產生gap
查看>>