社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
从事Java开发的同学,或多或少都听说过这样一句话,String是不可变的
,可你是否想过为什么?还有人认为String
是可变的,因为我们在实际开发中,经常写出下面这样的代码,String
的输出内容确是是改变了,这又是为什么呢?
// 代码0
String str = "hello"
str = "world";
System.out.println(str); // 输出world
在我们进入正题下,先解答下这个疑惑,这个清楚了,本篇的内容就很容易理解了!
在代码0中,输出结果确实是显示了,我们改变了str
的内容,可是String
不是不可变的吗?首先我们要先弄清楚String
的内部结构,String
是一个final
类,内部有一个private final char[] value;
,这个value
就是String
存储核心(之前说过,详情请看深入浅出Java String)。而String
是引用类型的,所以不可变的是value
,而不是str
引用,看下图就明白了:
通过上图可以看到,我们只是改变来str
的引用指向,并未改变源String
的内容,所以我们常常所说的String
不变,是指它的内容,即那个char value[]
。
接下来进入正文,我们知道了String
不可变是因为它内部的final char value[]
,那么现在就开始改变这个value[]
。
大家都知道final
修饰的变量,一经赋值,就不允许在改变,但是在修饰数组时,我们却可以改变它的数组成员,看代码:
// 代码1
final int a = 1;
a = 2; // 编译错误
final char[] arr = {'h','e','l','l','o'};
char[] temp = {'w','o','r','l','d'};
arr = temp; // 编译错误
arr[0] = 't'; // 正确
arr[1] = 't'; // 正确
为什么会这样呢,因为final
修饰的是char[] arr
,所以这里的arr
是个引用,即这个引用不能改变,而char[]
的成员修改,不会影响到arr
,所以是正确的。
讲到这里,我们就应该知道了如何修改String
内部的value[]
了,但是还面临一个问题,即value[]
是private
的,这意味着只有它自己才能访问,但是我们可以用反射机制来打破它,强制修改私有成员!
// 代码2
String str = "hello";
Field value = String.class.getDeclaredField("value");// 获取String的value属性
value.setAccessible(true); //设置访问权限为true
char[] valueOfStr = (char[])value.get(str);//获取str上的value属性
valueOfStr[0] = 'Y'; //改变第一个字符
System.out.println(str); //输出Yello
在代码2中,我们通过反射机制,打破来私有变量的访问规则,强制修改了str
的内容。
了解了String
的内部结构,通过反射机制我们也可以改变String
的内容。但是,这里仅仅作为实验用,实际上不建议这样做,因为这样违背了封装性。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!