Java String类的疑惑:
- 创建
- 拼接
String是java的常用类之一,本质是字符数组char[]。String类是final类,不可被继承。关于String的创建,可以通过new来创建对象,也可以直接赋值。但是这两种创建方式的实现机制是不同的。提到对象的创建,我们就会想到堆、栈,这里还有一个string pool的概念,JVM维护一个String池,池中的string对象不可重复,string池不属于堆栈,而是一个常量池。
一、创建
创建一个String对象,主要有两种方式:
String str1 = new String("abc"); //在string池中创建abc对象,在堆中创建abc对象,栈中的str1指向该对象 String str2 = "abc";//在string池中查找abc对象,已存在,直接将栈中的str2指向该对象
仔细看两行注释,执行完第一行代码后,内存如图:
执行完第二行代码,内存如图:
可通过内存比较来验证:
先自己思考一下结果再往下继续啦!
String str1 = "abc"; String str2 = "abc"; String str3 = new String("abc"); System.out.println(str1 == str2); System.out.println(str1 ==str3); System.out.println(str1 == "abc"); System.out.println(str3 =="abc"); System.out.println(str1 == str3.intern()); System.out.println(str3 == str3.intern());
运行结果:
解析:
==比较的是内存地址,
str1==str2;// 都指向string池中的对象,所以返回true
str1==str3;//str1指向string池中的对象,str3指向堆中对象,所以,返回false
str1==“abc”; //都指向string池中的对象,所以返回true
str3==”abc“;//str3指向堆内存对象,另一个是string池中的对象,所以,返回false
str1==str3.intern(); //都指向string池中的对象,返回true
str3==str3.intern();//str3指向堆内存对象,str3.intern()指向string池中的对象,所以,返回false
intern()方法是返回字符串对象的规范化表示形式,也就是说当调用intern()时,如果string池中已经包含一个等于(equals)此string对象的字符串,则返回池中的字符串。
二、拼接
先来思考一下执行结果:
<span style="white-space:pre"> </span>String hello = "hello"; String hel = "hel"; String lo = "lo"; System.out.println(hello == "hel"+"lo"); System.out.println(hello == "hel"+"looo"); System.out.println(hello== "hel" + lo);
运行结果:
解析:
- 如果+连接的都是常量时,先判断string池中有没有hello,如果存在,直接返回其地址,不再重新创建。
- 如果+连接的有对象类型时,则直接在堆中生成一个新对象。
关于String拼接的继续思考:
由于String类是final的,也就是对象一旦创建,就不能改变其内在状态了,但是,拼接操作是要改变String的内部状态的,在这种矛盾下,要维护string的非可变性,只好在拼接完成后再创建一个新的String对象,也就是说,每执行一次拼接操作,都会产生新对象的产生。当大量指向拼接操作时,就会导致大量对象的创建,这样,就产生了性能问题。
为了解决这个问题,jkd为string类提供了一个可变的配套类StringBuffer。由于StringBuffer是可变的,拼接时仅仅是改变了内部数据结构,而不会创建新对象,因此,性能上有很大的提高。
String类的疑惑