在Java开发中,字符串使用的非常频繁,在内存中占据的比例相当高,JDK的设计大拿们早就意识到这点,对其进行了大量的优化。
一、认识String
String并非基本数据类型,却是最重要的引用数据类型,可以认为是对char数组的封装,提供许多有效的操作字符数组的方法。
查看String源码(JDK1.6)可以发现,String类主要由三部分组成:char数组、偏移量和String的长度。
`private static final class CaseInsensitiveComparator implements
Comparator, Serializable {
// 内容
private final char[] value;
// 偏移量
private final int offset;
// 长度
private final int count;
/**
* Creates an empty string.
*/
public String() {
value = EmptyArray.CHAR;
offset = 0;
count = 0;
}
}`
String对象的真实内容是由这三部分共同决定的,这就意味字符数组存储的字符并非全都有效,除了被offset和count截取部分,其余的空间就浪费了,其实这是设计上的一种以空间换时间的策略,以此来提高String对象的创建效率。
二、String对象的三个基本特点
a.不变性
b.针对常量池的优化
c.类的final定义
1.不变性
不变性是指String对象一旦生成,就不能再对它进行改变,其实质是不能改变该对象的内部状态,即成员变量的值,基于两点可以说String对象是不变的:1.没有提供set方法来改变这些成员变量;2.String类提供的处理方法都会创建一个新的对象,如replace(),substring(),原有的对象依然不变。这也是不变模式的典型应用。当然通过反射技术还是可以改变String的值。
那么为什么要将String对象设计成不变的呢?原因有三点:
1)字符串池(String pool)的需求 在Java中,当初始化一个字符串变量时,如果字符串已经存在,就不会创建一个新的字符串变量,而是返回存在字符串的引用。 例如: String string1=”abcd”; String string2=”abcd”; 这两行代码在堆中只会创建一个字符串对象。如果字符串是可变的,改变一个字符串变量,就会使另一个字符串变量指向错误的值。
2)缓存字符串hashcode码的需要 字符串的hashcode是经常被使用的,字符串的不变性确保了hashcode的值一直是一样的,在需要hashcode时,就不需要每次都计算,这样会很高效。
3)出于安全性考虑 字符串经常作为网络连接、数据库连接等参数,不可变就可以保证连接的安全性。
2.针对常量池的优化
当两个String对象拥有相同的值时,它们只引用常量池中的同一个拷贝。当同一个字符串反复使用时,这个技术可以大幅度节省内存空间。
public class StringDemo {
/**
* @param args
*/
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
System.out.println(str1==str2); // true
System.out.println(str1==str3); // false
System.out.println(str1==str3.intern()); // true
}
}
三、类的final定义
作为final类,意味着String类不能有任何子类。