关于java字符串编译优化问题
情景一:不好的字符串拼接习惯
起因是这样的:一个大牛在写了一篇关于java字符串优化问题的讲解,他提到:不要使用strObj+otherValue的方法将otherValue转换为字符串形式,因为底层操作会让你吓一跳的。那么底层的实质是怎么样的呢?他的意思是这样的:
比如: String s = "I have";
int total = 12;
Dog dog = new Dog(); //假设Dog类重写了toString方法
String msg = s + total+dog;
在运行时,msg的赋值语句会执行为: msg = new StringBuilder().append(s).append(total).append(dog.toString()).toString();
我们发现,运行时创建了一个匿名的StringBuilder对象,来拼接字符串,存储到缓冲区,最后调用toString方法返回拼接后的结果。显然,StringBuilder在这里小材大用了,而且消耗了内存资源,不可取。我发现很多人都喜欢写类似 ""+num的代码,我也是。所以以后需要注意了,特别是性能敏感的环境下。应该改用String.valueOf(value),或者包装类型的toString方法,比如Double.toString(value)。
如果需要对字符串进行频繁的修改操作,那就使用StringBuilder,或者StringBuffer(线程安全的),从而避免大量的中间字符串垃圾碎片。
情景二:为什么一个是true,一个是false
一位网友提到了这样一个问题:
String str = "abc";
String str1 = "ab" + "c";
String str2 = "ab";
String str3 = str2 + "c"; //试试运行这段代码,就会发现第一个为true 第二个为false ,why?
下面是我的解释:
这是因为javac的编译优化造成的。str1是由2个字符串常量拼接的,常量一定是不会改变的量,那么在编译阶段,javac就有胆量将它给简化一下:str1就优化为:str1="abc",又因为str也是"abc",所以str和str1共享了内存据“abc”,所以str和str1都指向"abc"。由于==是浅比较,比较的是字符串的内存地址,所以他们相等。
而str3的拼接中包含了一个变量str2,而变量是在运行时动态确定的,所以javac不敢再编译时对它优化。也就是说,str3会在运行时在堆中new出字符串对象"abc",显然它的地址和前面的"abc"的地址不一样,所以是false。
我对上面的程序导出jar后进行反编译,验证了我的猜想,结果如图:

为了进一步证实我的猜想,我把上面的代码改为:
String str = "abc"; final String str2 = "ab";
String str3 = str2 + "c"; System.out.println(str == str3); //打印出true
那么问题来了,不是说str2是变量的吗。怎么这次也打印是true呢?注意我给str2加上了修饰符final,声明str2位常量,那么同样的道理,javac也能保证str2不会改变,于是把str3优化为:str3="abc"。
反编译class文件截图:

注意:不要使用 == 去比较字符串,因为字符串时引用类型,== 比较的是内存地址,而不是字符串内容。请使用equals() 或者equalsIgnoreCase()。
只有字符串常量是共享内存的,而字符串变量或者运行时动态生成的字符串,则非如此。
关于java字符串编译优化问题的更多相关文章
- Java动态编译优化——提升编译速度(N倍)
一.前言 最近一直在研究Java8 的动态编译, 并且也被ZipFileIndex$Entry 内存泄漏所困扰,在无意中,看到一个第三方插件的动态编译.并且编译速度是原来的2-3倍.原本打算直接用这个 ...
- java中的字符串简介,字符串的优化以及如何高效率的使用字符串
简介 String最为java中最重要的数据类型.字符串是软件开发中最重要的对象之一,通常,字符串对象在内存中总是占据着最大的空间块.所以,高效处理字符串,将提高系统的整个性能. 在java语言中,S ...
- 15个问题自查你真的了解java编译优化吗?
摘要:为什么C++的编译速度会比java慢很多?二者运行程序的速度差异在哪? 了解了java的早期和晚期过程,就能理解这个问题了. 本文分享自华为云社区<你真的了解java编译优化吗?15个问题 ...
- 深入了解JVM虚拟机8:Java的编译期优化与运行期优化
java编译期优化 java语言的编译期其实是一段不确定的操作过程,因为它可以分为三类编译过程:1.前端编译:把.java文件转变为.class文件2.后端编译:把字节码转变为机器码3.静态提前编译: ...
- 90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(1)- JIT编译优化
麻烦大家帮我投一票哈,谢谢 经常听到 Java 性能不如 C/C++ 的言论,也经常听说 Java 程序需要预热,那么其中主要原因是啥呢? 面试的时候谈到 JVM,也有很多面试官喜欢问,为啥 Java ...
- java程序性能优化
一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...
- 35 个 Java 代码性能优化总结
前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...
- Java 代码性能优化总结
前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...
- Java代码性能优化总结
代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...
随机推荐
- jquery一些方法
1.重置表单 $('.window-form')[0].reset(); 2.序列化表单 params = $('.window-form').serialize(); $.trim()是jQuery ...
- easyui的validatebox重写自定义验证规则的几个实例
validatebox已经实现的几个规则: 验证规则是根据使用需求和验证类型属性来定义的,这些规则已经实现(easyui API): email:匹配E-Mail的正则表达式规则. url:匹配URL ...
- Android 蓝牙 BLE 开发笔记
最近公司头戴换了一块蓝牙4.0 BLE模块,所以我们Android组要适配 BLE.Android BLE 需要 4.3 以上系统,api 还是非常简单的, 第一步就是扫描, 扫描到设备后就可以连接了 ...
- ural 1272. Non-Yekaterinburg Subway
1272. Non-Yekaterinburg Subway Time limit: 1.0 secondMemory limit: 64 MB A little town started to co ...
- 三十分钟掌握STL
这是本小人书.原名是<using stl>,不知道是谁写的.不过我倒觉得很有趣,所以化了两个晚上把它翻译出来.我没有对翻译出来的内容校验过.如果你没法在三十分钟内觉得有所收获,那么赶紧扔了 ...
- BZOJ4182 : Shopping
最后选择的一定是树上的一个连通块,考虑树分治,每次只需考虑重心必选的情况,这就变成了以重心为根的树形依赖多重背包问题. 设f[x][j]表示从根节点到x这条路径及其左边的所有节点,以及以x为根的子树的 ...
- 洛谷 P1007 独木桥 Label:模拟
题目背景 战争已经进入到紧要时间.你是运输小队长,正在率领运输部队向前线运送物资.运输任务像做题一样的无聊.你希望找些刺激,于是命令你的士兵们到前方的一座独木桥上欣赏风景,而你留在桥下欣赏士兵们.士兵 ...
- oracle 存储过程 基础
差不多一年没写过存储过程,最近要写,发现基本忘了,google一番之后,觉得很有必要把基础的东西写下来备忘. 语句块定义: decalre -- 变量声明 var1 ); -- 仅声明 var2 ) ...
- MyBatis学习---使用MyBatis_Generator生成Dto、Dao、Mapping
由于MyBatis属于一种半自动的ORM框架,所以主要的工作将是书写Mapping映射文件,但是由于手写映射文件很容易出错,所以查资料发现有现成的工具可以自动生成底层模型类.Dao接口类甚至Mappi ...
- hdu Load Balancing
这道题题目表示看不懂,如果哪位明白题意的,还望在评论里留个言指导一下!