关于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代码性能优化总结
代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...
随机推荐
- Xamarin Android项目运行失败
Xamarin Android项目运行失败 错误信息:Build Failed: MonoDroid does not support running the previous version. P ...
- win7家庭版更改桌面图标
电脑 Win7家庭普通版 方法/步骤 1 选择左下角开始. 2 在搜索栏中,输入“ico”,选择“显示或隐藏桌面上的通用图标”. 3 出现桌面图标设置,选择“更改图标”.
- MapReduce多线程下的错误
最近在写一个MR调度程序,在以服务进程中同时开启了两个MapReduce线程.这两个MR共享同一份输入源,此时会造成Cast异常: java.lang.ClassCastException: org. ...
- 中国大数据六大技术变迁记(CSDN)
大会召开前期,特别梳理了历届大会亮点以记录中国大数据技术领域发展历程,并立足当下生态圈现状对即将召开的BDTC 2014进行展望: 追本溯源,悉大数据六大技术变迁 伴随着大数据技术大会的发展,我们亲历 ...
- css3 flex流动自适应响应式布局样式类
1.再说css3 flex 一旦一个容器赋予了display:flex属性,将会有以下特点: 项目无法设置浮动. 列表的样式会被清除. 无法使用vertical-align设置垂直对齐方式. 目前互联 ...
- [leetCode][016] Add Two Numbers
[题目]: You are given two linked lists representing two non-negative numbers. The digits are stored in ...
- CC150 - 11.1
Question: You are given two sorted arrays, A and B, where A has a large enough buffer at the end to ...
- COJ979 WZJ的数据结构(负二十一)
试题描述 请你实现一个数据结构,完成这样的功能: 给你一个N个点的图,初始状态无边. 每次加入一条双向边(u,v,w),若加入后没有构成一棵生成树,输出“Not Yet”,否则输出当前最小生成树的权值 ...
- MyBatis学习---使用MyBatis_Generator生成Dto、Dao、Mapping
由于MyBatis属于一种半自动的ORM框架,所以主要的工作将是书写Mapping映射文件,但是由于手写映射文件很容易出错,所以查资料发现有现成的工具可以自动生成底层模型类.Dao接口类甚至Mappi ...
- iOS开发中常见的问题
1.重复调用2次loadView和viewDidLoad 最好不要在UIViewController的loadView方法中改变状态栏的可视性(比如状态栏由显示变为隐藏.或者由隐藏变为显示),因为 ...