【每日一问】详细描述String的特性
String
1、不可变
String是封装的Char数组的对象
char[] a = {‘h’,’e’,’l’,’l’,’o’};
String s=new String(a);
我们简写为String s = “hello”;
在内存中本质是数组存储的数据,数组长度不可变,创建出来的字符串对象不可变,但是变量可变
s这个变量的值是可以改变的,“hello”这个字符串是不可变的
2、比较
String是引用类型,用==判断是否是同一个对象
使用符号进行的运算都在栈内存中完成,比如“=”,“==”等
因此比较的是引用地址或内存地址是否相等
因为字符串有不可变性,因此反复创建字符串是件很消耗内存的事,因此在内存中专门指定了一片区域来存储各种常量,而在常量这个区域专门有一个区域来存放字符串常量,叫做字符串常量池,它有一个特性就是,字符串是唯一的
例如,
String s1 = “hello”;
String s2 = “hello”;
s1==s2 true
创建了s1,字符串常量池有1个“hello”,当再创建s2时,因为也是”hello”,因此常量池中就不再创建了,s2直接指向之前创建的常量
因此s1==s2 true
String s3 = new String(“hello”);
String s4 = new String(“hello”);
只要看见new创建的对象就一定在堆内存,new表示申请一片新的空间去存储
s1 == s3 false
s3 == s4 false
s5 = “he”+”llo”;
s6 = “he”;
s6 += “llo”;
s7 = s1;
s5是由2个常量相加得到的,常量+常量=常量,这个过程在编译过程中就直接完成了,不需要等程序运行,所以在程序运行时,s5就等于“hello”
因此s1==s5 true
s6的值是 变量+常量 得到的,是一个变量,对于程序而言,变量只有在程序运行时才知道,而这时候得到的值绝对不可能在常量池里,所以,s6产生的值在堆内存里,而s1在常量池里
因此s1==s6 false
s7是的赋值是直接把s1的引用地址赋值
因此s1== s7 true
3、StringBuffer、StringBuilder
在高频率的字符串拼接时,5次以上,应该用StringBuffer和StringBuilder,不应该用String
StringBuffer是安全的
StringBuilder是不安全的
所谓的安全和不安全表现为,多个线程处理同一个数据的时候安全不安全
例如用StringBuilder = “abc”,有3个线程都要改变它的值,3个线程可能运行在同一时间点,那么这个值就不可控了
而StringBuffer就可以保证这一点
StringBuffer的效率要远远高于String
String的+=运算,每次都要创建新的字符串,每一次都要新申请内存空间
而StringBuffer是用空间换取时间的做法,开始就准备一块很大的空间(),每次拼接,直接在字符串后面拼接即可
下图展示了StringBuffer和String的不同
在不考虑多线程时,使用StringBuilder就可以了