String为什么要设计成不可变

String为什么要设计成不可变

String为什么要设计成final的?
设计成不可变的好处:
  • 允许string对象缓存hashCode

    • String 对象的哈希码被频繁的使用,所以不可变保证了哈希值的唯一性,不必每次都去计算哈希值,也是一种优化手段。

    • 不可变保证了HashSet和HashMap的键值的唯一性,是其键不可重复成为可能。

    • 访问的网络连接地址url,文件路径path,如果String 可变,会引起各种隐患。

  • 支持线程安全

  • 支持字符串常量池

    • 在大量使用字符串的情况下,可以节省内存空间,提高效率;如果常量池中已存在,就直接使用常量池中的字符串。常量池的最基本条件就是字符串的不可变性。
String怎么样实现不可变?

String类的属性源码:

  • 首先String类是final修饰的,不能被继承,方法就不会被随意重写;
  • 字符串底层实际就是封装的字符数组,value属性被final修饰,则字符数组的引用就没办法修改;
  • value属性是private修饰的,所以外界访问不到,同时String也没有提供setValue方法,所以字符串生成后不可变;

​ String类真的是一定不可变吗?我们使用反射就可以改变String的值,测试之后发现hashCode()值没变,但是打印的值确实变了,证明我们反射修改是成功的,但是我们平时不这样做。

​ 代码入下:

public static void changeStringByReflection() {
	String str = "Hello world";
	// 获取str对象的value属性
	Field valueOfStr = str.getDeclaredField("value");
	// 修改value属性的访问权限为可访问
	valueOfStr.setAccessible(true);
	// 获取value值
	char[] chr = (char[])valueOfStr.get("str");
	// 修改值
	chr[5] = '+';
	System.out.println(str); // 输出:Hello+World;
}
为什么要设计字符串常量池,意义是什么?

字符串常量池有助于Java运行时节省大量空间,虽然创建字符串时需要更多的时间,耗费高昂的时间与空间代价。

也是享元模式的实例。

为了让数据不冲突进行共享。

jdk1.7及之后String类的intern()用法:

public static void main(String args[]) {
    String s4 = new String("ab") + new String("cde");
    String s5 = "abcde";
    s4.intern();
	// 此时由于s5的时候,字符串常量池中已经存在了abcde,所以s4.intern()的时候返回的是常量池中的引用
    System.out.println(s4 == s5); // false
}
public static void main(String args[]) {
    String s4 = new String("ab") + new String("cde");
    s4.intern();
    String s5 = "abcde";
	// 由于s4.intern()方法调用之前,常量池中是没有abcde的,所以调用后常量池中是s4的引用,所以s5指向常		量池的时候,指向的是s4的引用
    System.out.println(s4 == s5); // true
}
public static void main(String args[]) {
    String s4 = new String("abcde");
    s4.intern();
    String s5 = "abcde";

    System.out.println(s4 == s5);
}
// 结合上面两个例子,说明new String("abcde")的时候,如果常量池中不存在“abcde”,则会创建两个对象,首先再常量池创建“abcde”,然后再new堆空间中创建一个对象。

对于final修饰的字段,编译期直接进行了常量替换(而对于非final字段则是在运行期进行赋值处理的)。
final String str1=”ja”;
final String str2=”va”;
String str3=str1+str2;
在编译时,直接替换成了String str3=”ja”+”va”,再次替换成String str3=”java”

原文链接:https://blog.csdn.net/soonfly/article/details/70147205

new string(abc)创建了几个对象

一个或两个,当常量池中没有abc的时候,创建了两个。

// 一下代码会创建几个对象
String str = "abc" + "def"; // 创建一个"abcdef"对象,编译的时候直接优化为常量"abcde"
String str = "abc" + new String("def"); // 创建了4个字符串对象,1个StringBuilder对象

创建一个"abcdef"对象,编译的时候直接优化为常量"abcde"
String str = “abc” + new String(“def”); // 创建了4个字符串对象,1个StringBuilder对象


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值