Java 字符串处理的一些小细节
2015-11-24 16:50
447 查看
转载请注明出处:王亟亟的大牛之路
讲今天的内容之前温故一些理论知识?(部分理论知识来源于网上,谢谢开源大家庭)
1.什么是指针?—指针是指向内存中的地址,该地址就是存储变量的值。
2.Java中没有了指针,那以什么东西来替代指针相应的功能?
—java中我们所谓的对象引用就是指针,只是没有像C/C++中给出了一个明确的定义。java是为了避免指针带来的使用上的麻烦,所以就使用对象的引用来代替了指针。
3.那么这些对象的引用又存放在哪?
—java中的内存分为堆内存(heap)和栈内存(stack)。堆就是用来存放对象的,而栈则是存放一些数据基本类型的值。
一.引用
平时字面量创建就是简单的String wjj = "Hello";
JVM检测这个字面量,这里我们认为没有内容为Hello的对象存在。JVM通过字符串常量池查找不到内容为Hello的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量wjj。
然后又给第二个对象赋值,如:
String wjj1 = "Hello";
因为在我们的常量池中已经有了hello这个对象,所以把已经存在的字符串对象的引用返回给变量wjj1。
测试下这两个对象指向同一个Hello:
String Wjj= "Hello"; String Wjj2="Hello"; System.out.println(Wjj==Wjj2); System.out.println(Wjj.equals(Wjj2)); 结果: true true
那除了直接 String Wjj= “Hello”;我们还用 new String的 方式,像这样:
String Wjj2=new String("Hello");
结果还是一样的给我们的Wjj2这个对象赋值了Hello,那么打印的结果会有区别么?
String Wjj= "Hello"; String Wjj2=new String("Hello"); System.out.println(Wjj==Wjj2); System.out.println(Wjj.equals(Wjj2)); 结果: false true
“==”和equals的区别只后会再加解释,基础还是很重要的哈哈!
我们可以看到当我们使用了new来构造字符串对象的时候,这两个变量指向的为不同的对象,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。
二.修改值相同但地址不同的引用
对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。
String Wjj1=Wjj.intern(); System.out.println(Wjj1==Wjj); 结果: true
-概念:
1.字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。
2.因为字符串常量池中持有了共享的字符串对象的引用,这就是说是不是会导致这些对象无法回收?
首先问题中共享的对象一般情况下都比较小。据我查证了解,在早期的版本中确实存在这样的问题,但是随着弱引用的引入,目前这个问题应该没有了。
那么
String Wjj3="a"+"b"+"c";又等于"abc"么?
String Wjj= "abc"; String Wjj2="a"+"b"+"c"; System.out.println(Wjj==Wjj2); System.out.println(Wjj.equals(Wjj2)); 结果: true true
其实是在编译之前就已经进行了优化所以他们指向了同一个对象
三.String对象
在Java中,String对象是不可变的(Immutable)。在代码中,可以创建多个某一个String对象的别名。但是这些别名都是的引用是相同的。比如wjj2和wjj都是”hello”对象的别名,别名保存着到真实对象的引用。所以wjj2 = wjj
String Wjj= "hello"; String Wjj2=Wjj; System.out.println(Wjj==Wjj2); System.out.println(Wjj.equals(Wjj2)); 结果: true true
在Java中,唯一被重载的运算符就是字符串的拼接相关的。+,+=。除此之外,Java设计者不允许重载其他的运算符。
字符串操作的性能问题
String s1="a" ; String s2="b"; String s3="c"; String s4=s1+s2+s3; System.out.println(s4); 结果: abc
要得到上面的S4,就会S1和S2拼接生成临时一个String对象t1,内容为ab,然后有t1和s3拼接生成最终我们需要的s4对象,这其中,产生了一个中间的t1,而且t1创建之后,没有主动回收,势必会占一定的空间。如果是一个很多(假设上百个,多见于对对象的toString的调用)字符串的拼接,那么代价就更大了,性能一下会降低很多。
编译器的优化处理
真的会有上面的性能代价么,字符串拼接这么常用,没有特殊的处理优化么,答案是有的,这个优化进行在编译器编译.java到bytecode时。
一个Java程序如果想运行起来,需要经过两个时期,编译时和运行时。在编译时,Java 编译器(Compiler)将java文件转换成字节码。在运行时,Java虚拟机(JVM)运行编译时生成的字节码。通过这样两个时期,Java做到了所谓的一处编译,处处运行。
Java编译器做的优化,当Java编译器遇到字符串拼接的时候,会创建一个StringBuilder对象,后面的拼接,实际上是调用StringBuilder对象的append方法。这样就不会有我们上面担心的问题了。
SO,我们来测试一下:
public static void main(String[] asa) { String value=""; long a=System.currentTimeMillis(); for(int k=0;k<9000;k++){ value=value+k; } System.out.println("a的时间差= "+(System.currentTimeMillis()-a)); StringBuilder stringBuilder=new StringBuilder(); long b=System.currentTimeMillis(); for(int f=0; f<9000; f++){ stringBuilder.append(f); } System.out.println("b的时间差="+(System.currentTimeMillis()-b)); } 结果: a的时间差= 1137 b的时间差=4
性能差距明显哦!!!
相关文章推荐
- Java 字符串处理的一些小细节
- eclipse中文字体大小修改,让中英文字体协调
- 当spring 容器初始化完成后执行某个方法
- Java中的static关键字解析
- java正则表达式(HTML提取)
- Spring 中关于资料上传与 MultipartResolver
- Eclipse创建简单helloworld的servlet小程序
- Eclipse HibernateTools安装
- java.lang.noclassdeffounderror:com/mchange/v2/ser/Indirector
- Java去除掉HTML里面所有标签,
- 基于注释的Spring cache 缓存介绍
- 如何使用java的正则表达式提取html标签?
- 《JAVA与模式》之合成模式
- Quartz Spring与Spring Task总结
- 教你学会java基础多线程系列文章之基础篇
- Java正则表达式提取html纯文本
- Java基础---IO流(上)
- ubuntu中netbean ide中文乱码
- 数组的基本操作(一)
- java正则表达式取得html标签内的内容