@TryLoveCatch
2022-04-15T10:40:10.000000Z
字数 2229
阅读 591
Java知识体系
String是Java语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的Immutable类,被声明成为final class,所有属性也都是final的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的String对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。
String类型的初始化在Java中分为两类:
String str = "abc";
String str = new Sring("abc);
前者在常量池中开辟一个常量,并返回相应的引用。
后者是在堆中开辟一个常量,再返回相应的对象。
所以,两者的引用肯定是不同的
字符串常量池存在于方法区,后续java版本好像放到了堆里面。
String str1 = “abc”;
String str2 = “abc”;
String str3 = “abc”;
String str4 = new String(“abc”);
String str5 = new String(“abc”);
public native String intern();
该方法是一个本地方法,底层调用c++的方法实现,会返回指向常量池的地址。
该方法的目的是提示JVM把相应字符串缓存起来,以备重复使用。
在我们创建字符串对象并调用intern()方法的时候,如果已经有缓存的字符串,就会返回缓存里的实例,否则将其缓存起来。
字符串常量池:"abc" : 1个
堆:new String("abc") :1个
总共 :2个
字符串常量池:"A","B","AB" : 3个
堆:new String("AB") :1个
总共 :4个
字符串常量池:"ABC" : 1个
堆:new String("ABC") :1个
总共 :2个
String是Java语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的Immutable类,被声明成为final class,所有属性也都是final的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的String对象。由于字符串操作的普遍性,所以相关操作的效率往往对应用性能有明显影响。
StringBuffer是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用append或者add方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是StringBuilder。
StringBuffer实现的一些细节,它的线程安全是通过把各种修改数据的方法都加上synchronized关键字实现的,非常直白。
StringBuilder是Java 1.5中新增的,在能力上和StringBuffer没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。默认情况下,Java会把我们用 + 拼接的字符串,自动转换为StringBuilder。
为了实现修改字符序列的目的,StringBuffer和StringBuilder底层都是利用可修改的(char,JDK 9以后是byte)数组,二者都继承了AbstractStringBuilder,里面包含了基本操作,区别仅在于最终的方法是否加了synchronized。
另外,这个内部数组应该创建成多大的呢?如果太小,拼接的时候可能要重新创建足够大的数组;如果太大,又会浪费空间。目前的实现是,构建时初始字符串长度加16(这意味着,如果没有构建对象时输入最初的字符串,那么初始值就是16)。我们如果确定拼接会发生非常多次,而且大概是可预计的,那么就可以指定合适的大小,避免很多次扩容的开销。扩容会产生多重开销,因为要抛弃原有数组,创建新的(可以简单认为是倍数)数组,还要进行arraycopy。