java编译器对string常量表达式的处理和优化

Wesley13
• 阅读 396

首先把问题摆出来,先看这个代码 

String a = "ab"; 
String b = "a" + "b"; 
System.out.println((a == b));

打印结果会是什么?类似这样的问题,有人考过我,我也拿来考过别人(蛮好玩的,大家也可以拿来问人玩),一般答案会是以下几种: 

1.true 
    "a" + "b" 的结果就是"ab",这样a,b都是"ab"了,内容一样所以"相等",结果true 
    一般java新人如是答。 

2.false 

    "a" + "a"会生成新的对象"aa",但是这个对象和String a = "ab";不同,(a == b)是比较对象引用,因此不相等,结果false ,对java的String有一定了解的通常这样回答。 

3.true 
    String a = "ab";创建了新的对象"ab"; 再执行String b = "a" + "b";结果b="ab",这里没有创建新的对象,而是从JVM字符串常量池中获取之前已经存在的"ab"对象。因此a,b具有对同一个string对象 的引用,两个引用相等,结果true. 
    能回答出这个答案的,基本已经是高手了,对java中的string机制比较了解。 
    很遗憾,这个答案,是不够准确的。或者说,根本没有运行时计算b = "a" + "b";这个操作.实际上运行时只有String b = "ab"; 
    3的观点适合解释以下情况: 

    String a = "ab"; 
    String b = "ab"; 
    System.out.println((a == b));

    如果String b = "a" + "b";是在运行期执行,则3的观点是无法解释的。运行期的两个string相加,会产生新的对象的。(本文后面对此有解释) 

4.true 
    下面是我的回答:编译优化+ 3的处理方式 = 最后的true 

    String b = "a" + "b";//编译器将这个"a" + "b"作为常量表达式,在编译时进行优化,直接取结果"ab",这样这个问题退化 
    String a = "ab"; 
    String b = "ab"; 
    System.out.println((a == b));

    然后根据3的解释,得到结果true 
    这里有一个疑问就是String不是基本类型,像 

    int secondsOfDay = 24 * 60 * 60;

    这样的表达式是常量表达式,编译器在编译时直接计算容易理解,而"a" + "b" 这样的表达式,string是对象不是基本类型,编译器会把它当成常量表达式来优化吗? 
    下面简单证明我的推断,首先编译这个类: 

public class Test { 
    private String a = "aa"; 
}

       复制class文件备用,然后修改为 

public class Test { 
    private String a = "a" + "a"; 
}

    再次编译,用ue之类的文本编辑器打开,察看二进制内容,可以发现,两个class文件完全一致,连一个字节都不差. 
    ok,真相大白了.根本不存在运行期的处理String b = "a" + "b";这样的代码的问题,编译时就直接优化掉了。 

下面进一步探讨,什么样的string + 表达式会被编译器当成常量表达式? 
String b = "a" + "b"; 
这个String + String被正式是ok的,那么string + 基本类型呢? 

String a = "a1"; 
String b = "a" + 1;    
System.out.println((a == b));  //result = true 

String a = "atrue"; 
String b = "a" + true; 
System.out.println((a == b));  //result = true 

String a = "a3.4"; 
String b = "a" + 3.4; 
System.out.println((a == b));  //result = true

可见编译器对string + 基本类型是当成常量表达式直接求值来优化的。 
再注意看这里的string都是"**"这样的,我们换成变量来试试: 

String a = "ab"; 
String bb = "b"; 
String b = "a" + bb; 
System.out.println((a == b));   //result = false

这个好理解,"a" + bb中的bb是变量,不能进行优化。这里很很好的解释了为什么3的观点不正确,如果String+String的操作是在运行时进行的,则会产生新的对象,而不是直接从jvm的string池中获取。 
再修改一下,把bb作为常量变量: 

String a = "ab"; 
final String bb = "b"; 
String b = "a" + bb; 
System.out.println((a == b));   //result = true

竟然又是true,编译器的优化好厉害啊,呵呵,考虑下面这种情况: 

String a = "ab"; 
final String bb = getBB(); 
String b = "a" + bb; 
System.out.println((a == b));    //result = false 
private static String getBB() { 
return "b"; 
}

看来java(包括编译器和jvm)对string的优化,真的是到了极点了,string这个所谓的"对象",完全不可以看成一般的对象,java对string的处理近乎于基本类型,最大限度的优化了几乎能优化的地方。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
2年前
Hive 删除行, 表 ,清空表
删除行A表数据如下id(String)       name(String)\1                       aaa2                      bbb3                      ccc\
Stella981 Stella981
2年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这