1. 在观察String类的concat方法时,发现了个没见过的String构造方法
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
2. 发现它传了一个true进去,点进去后
发现它对传进去的true没有做任何操作,这是一种“方法重载思想”,传一个boolean只是为了区分方法
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
每次new String 操作,都会赋值给final修饰的value。
3. 那么这个方法和不传boolean的有什么区别呢?
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
可以观察到方法的修饰符不同,一个是public修饰符,一个是默认修饰符,也就是只有同包才能访问。所以我们是使用不了的,因为如果交给我们使用的话,可能会违反String是不可修改的原则的。
- 例如如下代码:不能运行,只是示范
此时传入的b是引用,s的value中保存的也是b的引用,所以可以认为此时的b与String中的value是同一个对象,此时修改b[1]的值的时候,String中final修饰的value就被修改了,很明显不符合String的定义。
char [] b = {'b','c','1'};
String s = new String(b, true);
b[1] = 'a'
而直接传入char[]数组的构造方法,是调用数组拷贝,将传入的值一一赋值到String内置的value数组中,他们两个是不同的两个对象,也就保证了String类的不可修改
4. 最后我们来强行调用一下,利用反射
private static void test07() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
char[] a = {'1','f','l'};
Class<String> clazz = String.class;
Constructor<String> constructor = clazz.getDeclaredConstructor(char[].class, boolean.class);
constructor.setAccessible(true);
String s = constructor.newInstance(a, true);
System.out.println(s);
//此时修改a[1]的值
a[1]='c';
System.out.println(s);
}
我们观察打印输出,可以发现,String对象被我们修改了
1fl
1cl