String不变表现形式
String str = "ABCabc";
System.out.println("str="+str);
str = "123456";
System.out.println("str="+str);
打印结果
str=ABCabc
str=123456
首先创建一个String对象str,然后让s的值为“ABCabc”, 然后又让s的值为“123456”。 从打印结果可以看出,s的值确实改变了。那么怎么还说String对象是不可变的呢? 其实这里存在一个误区: str只是一个String对象的引用,并不是对象本身。对象在内存中是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个4字节的数据,里面存放了它所指向的对象的地址,通过这个地址可以访问对象。 也就是说,str只是一个引用,它指向了一个具体的对象,当str=“123456”; 这句代码执行过之后,又创建了一个新的对象“123456”, 而引用str重新指向了这个新的对象,原来的对象“ABCabc”还在内存中存在,并没有改变。
内存结构:
String为什么不可变?
查看源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
通过查看源码我们发现String底层的是final
修饰的char[]
数组。
String真的不可变吗?
我们可以通过反射改变其值:
public static void main(String[] args) throws Exception {
//创建字符串"Hello World", 并赋给引用s
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
//改变value属性的访问权限
valueFieldOfString.setAccessible(true);
//获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);
//改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
}
结果
s = Hello World
s = Hello_World