“+” 是怎么连接字符串的?(JDK1.7及以上)
总结:
使用 “+” 连接字符串时,实际上是使用临时创建的StringBuilder对象来辅助完成的。
对于编译时常量,在编译后直接计算出字符串的值,而不会在运行时创建临时的StringBuilder对象来完成字符串连接。
在循环中对String对象进行连接,应该直接使用StringBuilder代替 “+”,这样可以提高性能。
注意: 当使用运算符 “+” 连接字符串时,如果两个操作数都是编译时常量,则在编译时期就会计算该字符串的值,而不会在运行时创建StringBuilder对象。
final String s = "abc";
String x = "abc" + "def"; // 两个操作数都是常量,运行时不会创建StringBuilder对象
String y = s + "def"; // s和"def"都是编译时常量,不会创建StringBuilder对象,实际上x和y指向同一个对象,即"abcdef"
String z = y + "abc"; // y是变量,则在运行时会创建StringBuilder对象
不可修改的String对象
<1> 问:String对象一经创建,不能修改,为什么?
因为String类是final类型的,无法继承该类。
其所有的成员变量都是private的,并且没有提供修改私有成员变量的公有(public)方法
对String对象的操作都没有修改当前对象,而是新创建一个对象
<2> 问:把String对象设计成不可修改有什么好处吗?
最大好处就是可以实现资源共享,多线程操作时,具有线程安全性。
总结三点:
- String类是final类型的,其对象一旦创建,不可修改。
- String类那些看似修改字符序列的方法实际上都是返回新创建的String对象,而不是修改自身对象。
- String对象不可改变,因此具有线程安全性,可自由实现共享。
String类的内部实现
在String类内部,使用一个字符数组char[]来维护字符序列。
private final char value[];
问:String的最大长度是多少?
String的最大长度也就是字符数组char[]的最大长度,理论上为int类型的最大值,即2147483647,实际上,一般可获取的最大值小于理论最大值。
申请一个int最大值长度字符数组:
char c = new char[Integer.MAX_VALUE]; // 报错
报错:一个char类型占用2字节,Integer.MAX_VALUE个char类型接近于4GB大小,申请这么大一块连续内存空间,导致内存溢出。
//加入Java开发交流君样:756584822一起吹水聊天
分析:Java中的对象是分配在堆上的,默认的堆空间的最大值是256MB,在理想的情况下,只要我们将最大Java堆设置的足够大,就可以申请到最大的字符长度,即Integer.MAX_VALUE。
java -Xmx1G com.fan.fragmentlearning.str.StringDemoMain – 设置Main方法最大Java堆
String常量池
<1> 什么是String常量池?
String常量池是String类内部私有的,能够自动将String字面常量加入其中。
起初,常量池是空的,当程序中出现String字面常量时,会在常量池中搜索是否存在该String对象,即使用String类的equals方法来判断,如果不存在,就将这个字面常量加入常量池中,并返回该对象;否则直接返回常量池中的对象。
<2> String字面常量和String常量表达式都会加入常量池中。
<3> 满足什么条件才算是String常量表达式呢?
即就是在编译的时候就可以确定其值的String类型表达式。编译器的原则是:能在编译期间计算的,就不会留到运行时再去计算。
第一种: 表达式全部由String字面常量拼接
String s = "a" + "b" + "c";
第二种: 表达式由String字面常量,基本类型字面常量,final修饰的String引用,final修饰的基本数据类型任意组合组成。
String s = "a" + 5; // String常量表达式final String str = "a";
String s = "bc" + str; // String常量表达式final int num = 5;
String s = "a" + num; // String常量表达式String s = str + num; // String常量表达式
<4> intern方法 - 拘留字符串
如果需要将某个String对象加入常量池中,就可以调用intern方法来完成,这个操作也称作拘留字符串。
系统自动将String字面常量与String常量表达式的字符串值加入常量池中,也是通过调用intern方法来实现的。
要点总结:
String类维护一块特殊的区域,称为常量池。因为String对象是不可改变的,因此没有必要创建两个相同的String对象。只需将String对象加入常量池,在需要的时候取出,这样即可实现String对象的共享。
在程序中出现String编译时常量(String字面常量与String常量表达式),会自动调用intern方法,如果常量池中含有相等的String对象(使用String类的equals方法来判断),则直接返回常量池中的对象;否则将对象加入常量池中并返回该对象。
对于运行时创建的String对象(非String编译时常量),会分配到堆中,系统不会自动调用intern方法拘留该对象,不过我们依然可以自行调用该对象的intern方法对该对象进行拘留。
最后,祝大家早日学有所成,拿到满意offer