字符串在程序中被广泛使用,每种编程语言都对字符串进行专门的处理。Java中的字符串作为对象存在,底层具有多重特性。一、String的特点String最大的特点就是不可变。底层使用数组存储对应的值:privatefinalbyte[]value;可以看到,变量用final修饰是为了避免修改引用,用private是为了让其他类不能直接使用。这里只保证引用的不变性。如何保证值的不变性?其实价值是需要从实现上来保证的。String中所有引起值变化的方法都会产生一个新的对象,比如拼接、剪切等操作,都会被复制然后操作。甚至,类也用final修饰,保证没有子类继承String再修改值。我们来看一个例子,下面的代码执行后会输出“aaa”还是“bbb”?publicstaticvoidmain(String[]args){Strings="aaa";变化);System.out.println(s);}publicstaticvoidchange(Strings){s="bbb";}这里最后的结果是输出“aaa”,因为赋值的时候,s的值没有变,只是s的引用变了,而引用是方法的形参,变了不影响调用者,所以输出是“aaa”。2、为什么常量池的设计一定要是不可变的?因为有字符串常量池的存在,常量池的实现是因为大部分系统使用的字符串都大致相同,所以将常用的字符串缓存起来放在一个池中,这样可以重复使用,避免频繁创建对象造成的损失。如果String是可变的,则无法实现常量池。如下,如果s1改变了“ccc”的值,就会影响s2的使用。常量池除了缓存常用的字符串外,还提供了inter()方法让业务方将需要的值添加到池中。这里需要注意的是,由于Java6将常量池放在永久代(PermGen)中,所以不建议频繁使用inter,否则容易造成OOM。后续版本将常量池放在堆中进行管理,解决了这个问题。但是手动调用inter还是有一定的成本的,不仅污染了业务代码,而且在平时使用的时候也无法预知需要缓存什么。在G1GC的Intern机制中,直接在JVM层面进行优化,保证相同字符串的引用是相同的。3.不可变的魅力不可变的优点是什么?首先,它增加了代码的可读性。该代码主要用于维护。这样的设计更能传达出本身的本质;其次,它受到约束,避免因有意或无意的价值观变化而引起的问题。;再者,它天然支持并发场景,因为它是不可变的,所以不存在线程安全问题;最后,在性能方面,除了支持常量池设计之外,值得一提的是,hashCode的值也可以在一开始就创建出来,同时也因为这个特性用于缓存,所以String特别适合用作地图的关键。4、StringBuilder和StringBuffer虽然针对普通字符串进行了优化,但是如果业务中字符串操作过多,会产生过多的中间对象。StringBuilder和StringBuffer就是为了解决这类问题而设计的。它们都继承了AbstractStringBuilder,类中有一个变量成员变量byte[]value。两者的区别在于StringBuffer方法中增加了Synchronized,支持多线程场景。5.在应用业务中,如果对字符串的操作较少,可以使用String类,比如一些常量的使用,或者简单的存储业务需要的值;操作频繁,包括剪切、拼接、替换等,且线程安全需要使用StringBuffer,比如网关等场景;操作频繁,但没有线程安全要求,使用StringBuilder。
