面试必问:Java中的String为什么是不可变的?
面试必问:Java中String类型为什么设计成不可变的?
省流:String是一个类,通过value[]存储字符串,但是value被private和final修饰,也没有set方法,所以字符串无法修改,硬要修改的话,可以利用反射机制修改value数组元素
根据下面实例,我发现了String对象
明明可以修改!请问你真的修改的了String对象
吗?
public class Test{
public static void main(String[] args){
String a = "牛马问题";
System.out.println(a);
a = "什么是牛马";
System.out.println(a);
}
}
输出:
牛马问题
什么是牛马
其实我在上面已经两次对String对象
进行标注了,那你觉得上述示例中哪个才是String对象
呢?是a?还是“牛马问题”?还是“什么是牛马”?下面我来给你们再细化一下这段代码。
public class Test{
public static void main(String[] args){
String a = new String("牛马问题");
System.out.println(a);
a = new String("什么是牛马");
System.out.println(a);
}
}
输出:
牛马问题
什么是牛马
有的童鞋在心中有些思路了,但也有可能还存在疑虑。其实String a不是String 对象
,真正的String对象
是通过new String()
在JVM的堆中创建出来的,String a只是String对象
的引用。所以不要再纠结为什么String a可以改变了。
String对象为什么不能改变,顾名思义,就是String对象的值不能改变。我们先来看看String的值是如何存储的,再看看为什么不能改变存储的值。
String 对象的值一般通过value数组变量存储,我们可以看到这个数组被final
修饰,那就是说无法改变value数组的地址,从一而终。
/** The value is used for character storage. */
private final char value[];
那有同学就问了,我们可以改变value数组里面的值呀?真是个大聪明,你看看String类里面这个value数组变量是不是被private
修饰了,那我们只能通过set()方法来改变value数组的元素。可是String类没有提供value数组变量的set()方法!
这下就给你讲明白了为什么String类型是不可变的
面试的时候我们只是解释上面的原因其实不是那么尽善尽美,想要更好的去加薪去装逼,我们还需更进一步回答。
别忘了我们的反射机制,在通常情况下,他可以做出一些违反语言设计原则的事情。这也是一个技巧,每当面试官问一些违反语言设计原则的问题,你就可以拿反射来反驳他。
public class Test{
public static void main(String[] args){
String str = "牛马问题";
System.out.println(str);
//通过发射获取String内部value数组变量
Field field = String.class.getDeclareField("value");
//作用就是能够正常的访问私有属性
field.setAccessible(true);
char[] value = (char[])field.get(str);
//把字符串第一个字符改变
value[0] = '神';
}
}
输出:
牛马问题
神马问题
String对象的不可变性,导致每次修改值都要创建新的对象,性能肯定就很慢,没有的对象还要GC来清除,性能就更低了。不可变
线程安全
性能低
StringBuffer对象可以改变值,性能就提升了不少啦。但是也要面临着线程同步的问题,所以加了synchronized进行同步,耗费了一点点性能。可变
线程安全
性能较高
StringBuilder对象也可以改变值,但是这家伙为了追求性能,连同步都不要了,所以是线程不安全的。可变
线程不安全
性能最高
我的“牛马问题”String对象
创建了但是没有用,只会占着内存,以后我可不敢随便创建String对象
了。我觉得你是多虑了,String a引用了"什么是牛马"String对象
后,“牛马问题”String对象
没人引用,JVM不一会儿就把它当垃圾收走了。
public class Test{
public static void main(String[] args){
String a = "牛马问题";
System.out.println(a);
a = "什么是牛马";
System.out.println(a);
}
}
输出:
牛马问题
什么是牛马
当你看完文章后,又不留下点什么,那么这篇知识不一会儿就被你的大脑当垃圾清除掉的哟~