方式1:String str = new String("123");
方式2:String str2 = "123";
看一下内部源码:
里面有两个比较重要的变量字符串的hash值以及一个char类型的数组(这里用到了final空白,编译器会保证在使用的时候一定会被初始化,其实这样不仅保留了final只能被赋值一次的特性还有更好的扩展性),至于构造方法是用一个String类型接收的而我们传入的是"123",那么这个original是怎么来的呢,借用网上的观点在java中如果值被双引号引起来如本例中的"123"那么jvm会先去常量池中查看有没有该对象有就直接返回没有就把它放入常量池,所以本例中的str和str2的hash值是一样的,但是一般来说都不会去new String因为new总是会去堆中开辟一个内存空间来存放这个new出来的对象所以都是直接用第二种方式最好。
现在已经知道String里面用的是数组的形式,看几个常用的方法:
1:str.length
//直接返回的是这个数组的长度
public int length() {
return value.length;
}
2:str.equals
public boolean equals(Object anObject) {
if (this == anObject) {//两个对象的引用相等的话直接返回true
return true;
}
if (anObject instanceof String) {//Object对象不属于String的话直接false
String anotherString = (String)anObject;
int n = value.length;//拿到本地数组的长度
if (n == anotherString.value.length) {//比较本地数组和传进来的字符串数组的长度
//这里就是一个字符一个字符的比较,只有全部相等的时候才返回true否则返回false
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
下面来看一下string为什么不可变,以subString为例
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
//上面就是一些数组越界的常规判断
//主要是这里如果发现是从0截到最后就直接返回字符串否则就new一个新的对象
//并把数组value和截取的长度传过去,其实从这里也就看出来了这就是string不可变的原因,其它的一些操作其实都是新new一个对象
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
}
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
//这里用到了数组拷贝继续往下看
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
public static char[] copyOfRange(char[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
//这里新创建了一个数组对象
char[] copy = new char[newLength];
//这里是真正的拷贝,使用native方法
//original是要被拷贝的数组,from是从拷贝的初始位置(左闭右开)
//copy是拷贝的目标数组,0表示从copy数组的第一个位置开始拷贝,最后一个参数是为了防止出现越界所以取最小值
//到此subString的整个过程就结束了,实际上就是创建了一个新的字符串对象和数组的拷贝
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength));
return copy;
}