java中对于String这个不可变的字符串对象,大家都有所了解, 但是使用字面常量定义String和new String(String original) 定义String以及使用new String(char value[])定义String具体有审核区别呢?
字面常量定义String
String name = "doublinglee";
String name1 = "doublinglee";
System.out.println("name|" + name + " - " + System.identityHashCode(name));
System.out.println("name1|" + name1 + " - " + System.identityHashCode(name1));
输出(java8)
name|doublinglee - 2018699554
name1|doublinglee - 2018699554
这里java首先会在字符串常量池中查找这个字符串如果存在,则直接返回该字符串的引用地址;所以两个字符串打印出的hashCode(此处是原始的hashcode,而不是String重载后)
new String(String original) 定义
String name = "doublinglee";
String name1 = "doublinglee";
String name2 = new String("doublinglee");
System.out.println("name|" + name + " - " + System.identityHashCode(name));
System.out.println("name1|" + name1 + " - " + System.identityHashCode(name1));
System.out.println("name2|" + name2 + " - " + System.identityHashCode(name2));
输出(java8)
name|doublinglee - 2018699554
name1|doublinglee - 2018699554
name2|doublinglee - 1311053135
此时name3定义的字符串打印出的hashcode明显不同,说明创建了一个新的字符串对象;
接下来看一下通过反射强制修改String的内容(为了验证需要,大家在业务环境中不要使用,否则会改变String不可变的规则)
String name = "doublinglee";
String name1 = "doublinglee";
String name2 = new String("doublinglee");
try {
Field charsField = String.class.getDeclaredField("value");
charsField.setAccessible(true);
char[] object = (char[])charsField.get(name);
System.out.println(object.length);
object[0] = 'P'; // 修改字符串第一个字符
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("name|" + name + " - " + System.identityHashCode(name));
System.out.println("name1|" + name1 + " - " + System.identityHashCode(name1));
System.out.println("name2|" + name2 + " - " + System.identityHashCode(name2));
输出(java8)
name|Poublinglee - 1311053135
name1|Poublinglee - 1311053135
name2|Poublinglee - 118352462
为什么name2也变了呢?
再看下增加new String(char value[])的创建方式
String name = "doublinglee";
String name1 = "doublinglee";
String name2 = new String("doublinglee");
String name3 = new String(name.toCharArray());
try {
Field charsField = String.class.getDeclaredField("value");
charsField.setAccessible(true);
char[] object = (char[])charsField.get(name);
System.out.println(object.length);
object[0] = 'P'; // 修改字符串第一个字符
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("name|" + name + " - " + System.identityHashCode(name));
System.out.println("name1|" + name1 + " - " + System.identityHashCode(name1));
System.out.println("name2|" + name2 + " - " + System.identityHashCode(name2));
System.out.println("name3|" + name3 + " - " + System.identityHashCode(name3));
输出(java8)
name|Poublinglee - 1311053135
name1|Poublinglee - 1311053135
name2|Poublinglee - 118352462
name3|doublinglee - 1550089733
为什么name3没有变化呢?
带着疑问去看String的这两个构造方法
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
发现new String(String original) 其实只是创建一个String外壳,内在的char[]其实是共用的,这说明不管你用new String(String original) 创建多少个对象,只要字符串一样,就会共用char[],真正的堆存储也会共用,避免了浪费;
而new String(char value[])是用了数组拷贝,原因也很简单,数组是你传进来的,为了保证String的不可变属性,只能拷贝,不能复用。
以上分析但愿对您有所帮助;