面试必问:Java中String类型为什么是不可变的?

面试必问: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的值是如何存储的,再看看为什么不能改变存储的值。

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,那就再简述几句StringBuffer跟StringBuilder吧。

String对象的不可变性,导致每次修改值都要创建新的对象,性能肯定就很慢,没有的对象还要GC来清除,性能就更低了。不可变 线程安全 性能低

StringBuffer对象可以改变值,性能就提升了不少啦。但是也要面临着线程同步的问题,所以加了synchronized进行同步,耗费了一点点性能。可变 线程安全 性能较高

StringBuilder对象也可以改变值,但是这家伙为了追求性能,连同步都不要了,所以是线程不安全的。可变 线程不安全 性能最高

补充一点JVM知识

我的“牛马问题”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);
	}
}	
输出:
牛马问题
什么是牛马

当你看完文章后,又不留下点什么,那么这篇知识不一会儿就被你的大脑当垃圾清除掉的哟~

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值