先看属性底层是char数组,一目了然可以看到,value[]是存储String的内容的,即当使用String str = “abc”;的时候,本质上,"abc"是存储在一个char类型的数组中的。**String底层的存储结构是一个字符类型的数组,同样也是被final修饰,因此一旦这个字符数组被创建后,value变量不可再指向其他数组,但是可以改变value数组中某一个元素的值。
/** The value is used for character storage. */ private final char value[];而hash是String实例化的hashcode的一个缓存。因为String经常被用于比较,比如在HashMap中。如果每次进行比较都重新计算hashcode的值的话,那无疑是比较麻烦的,而保存一个hashcode的缓存无疑能优化这样的操作。 hash用来保存某一个String实例自己的哈希值,可以说是哈希值的一个缓存,因此String特别适合放入HashMap中,作为key来使用。每次插入一个键值対时,不需要重新计算key的哈希值,直接取出key的缓存hash值即可,在一定程度上,加快了HashMap的效率。
/** Cache the hash code for the string */ private int hash; // Default to 0序列化id,用于判断序列化时候的版本啥的
/** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L;构造方法 String支持多种初始化方法,包括接收String,char[],byte[],StringBuffer等多种参数类型的初始化方法。但本质上,其实就是将接收到的参数传递给全局变量value[]。
public String() { this.value = "".value; this.coder = "".coder; }知道了String其实内部是通过char[]实现的,那么就不难发现length(),isEmpty(),charAt()这些方法其实就是在内部调用数组的方法。
public int length() { return value.length >> coder(); } public boolean isEmpty() { return value.length == 0; } public char charAt(int index) { if (isLatin1()) { return StringLatin1.charAt(value, index); } else { return StringUTF16.charAt(value, index); } } public static char charAt(byte[] value, int index) { checkIndex(index, value); return getChar(value, index); } public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String aString = (String)anObject; if (!COMPACT_STRINGS || this.coder == aString.coder) { return StringLatin1.equals(value, aString.value); } } return false; }