关于String的不可变特性及两道面试题的详解

String的不可变特性

众所周知,String是不可变的,可是它为什么不可变呢?
我们查看String的源代码就能知道。

  1. String中的属性都是private final的,这就意味着String的属性作为一个常量不可被修改。
  2. . String中存放着字符串的容器value本身是一个数组,数组的长度不可变。

但是,对于这样的代码:

		
		String s = "ABCabc";
		System.out.println("s = " + s);//s = ABCabc
		
		s = "abcdef";
		System.out.println("s = " + s);//s = abcdef

不少人会有疑问,这里String不是改变了吗?为什么还说String是不可变的呢?

什么是不可变?
不可变指的是String对象的不可变,对象中的属性方法局部变量不改变。上面的例子中,s并不是String的对象,只是String对象的引入,当执行s = "abcdef"这条语句时,只是将String对象的引用重新指向了一个新的String对象。原来的String对象并没有改变,仍然是在原来的空间中(随后会被JVM的垃圾回收机制回收)。

String两种创建方式的区别

String str1 = "abc";
String str2 = new String("abc");

第一种是通过字面量定义的方式:此时的str1的数据abc声明在方法区中的字符串常量池中。
第二种是通过new + 构造器的方式:此时的str2保存的是地址值,是数据在堆空间中开辟空间以后对应的地址值。
用堆栈图说明:
String两种创建方式的区别
两道面试题
1.

String s1 = "javaEE";
String s2 = "javaEE";

String s3 = new String("javaEE");
String s4 = new String("javaEE");

System.out.println(s1 == s2);//true
System.out.println(s1 == s3);//false
System.out.println(s1 == s4);//false
System.out.println(s3 == s4);//false

s1和s2是通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。地址相同,因此s1 == s2为true。
而s3和s4是通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。二者存放在堆空间中,且在堆空间中的地址不同,因此s3 == s4为false,s3 == s1为false,s34 == s1为false。
2.

String s1 = "javaEE";
String s2 = "hadoop";

String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;

System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false 
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false

String s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
****************************
String s1 = "javaEEhadoop";
String s2 = "javaEE";
String s3 = s2 + "hadoop";
System.out.println(s1 == s3);//false

final String s4 = "javaEE";//s4:常量
String s5 = s4 + "hadoop";
System.out.println(s1 == s5);//true

说明
String的拼接中,如果二者都是字面量的方式,则拼接后的字符串也在字符串常量池中,但如果其中有一个是变量,则拼接后的字符串就会在堆空间中。
而intern()方法,可以将拼接后的结果又存放在字符串常量池中,成为一个常量。
最后的final修饰的字符串,编译器在编译的时候就会就此字符串变量看作一个常量直接替换在拼接的字符串中,因此返回的结果也是一个常量,存放在字符串常量池中。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值