Java 中 String 为什么设计成 final 类?为什么它有“不可变性”?

JAVA herman 373浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

竟然有其他号主问我问题,惊到我了!而且这个问题还特简单,我严重怀疑他是看不起我!

“Java 中 String 为什么设计成 final 类?为什么它有’不可变性’?”

你们真的懂 Java 吗?

这真是一个简单不能在简单的问题。我们先来看看 final,它就是不想让你继承。说白了,java 不想让你继承 String 类。

为什么呢?因为它是一个数据类型,就这么简单。

那为什么它有“不可变性”呢?因为它的源代码限制了它不可变。为什么要限制呢?我们先来看看什么是“不可变性”吧!

什么是不可变性?

“不可变性”可别理解错了哈。“不可变性”不是你们 YY 的那个意思。

String 很多实用的特性,比如说“不可变性”,是工程师精心设计的艺术品!艺术品易碎!用 final 就是拒绝继承,防止世界被熊孩子破坏,维护世界和平!

String 不可变很简单,如下图,给一个已有字符串"abcd"第二次赋值成"abcedl",不是在原内存地址上修改数据,而是重新指向一个新对象,新地址。

图解 String 在堆栈上如何不可变

明白了为什么不可变性后,我们再来看看为什么不可变?

上面我已经提到了源代码,那我们就从源代码说起。

public final class String implements java.io.Serializable, 
  Comparable<String>, CharSequence {
    /** String本质是个char数组. 而且用final关键字修饰.*/
    private final char value[];
  ...
}

从源代码中可以看出,String 类的底层 value 是个 char[] 数组,而且是用 final 修饰的。final 修饰的字段创建以后就不可改变。

哦,原来如此。。。

请注意,你们不要被这个 final 迷惑了。因为虽然 value 是不可变,也只是 value 这个引用地址不可变。挡不住 Array 数组是可变的事实。Array 的数据结构看下图:

图解 Array 数组在堆栈中的存储原理

也就是说 Array 变量只是 stack 上的一个引用,数组的本体结构在 heap 堆。String 类里的 value 用 final 修饰,只是说 stack 里的这个叫 value 的引用地址不可变。没有说堆里 array 本身数据不可变。

还不明白?那我们就一起来看个例子吧。

final int[] value={1,2,3}
int[] xttblog = {4,5,6};
value = xttblog;  //编译器报错,final 不可变

value 用 final 修饰,编译器不允许我把 value 指向堆区另一个地址。但如果我直接对数组元素动手,分分钟搞定。

final int[] value = {1,2,3};
value [2] = 100;  //这时候数组里已经是 {1,2,100}
//或者更粗暴的反射直接改
final int[] array={1,2,3};
Array.set(array,2,100); //数组也被改成{1,2,100}

所以 String 的不可变,最关键的原因是因为 SUN 公司的工程师,在设计 String 的方法时,并没有主动去修改 Array 里的元素,没有暴露内部成员字段。

说白了,SUN 就是让 String 设计成一个数据类型。

private final char value[] 这一句里,private 的私有访问权限的作用都比 final 大。而且设计师还很小心地把整个 String 设成 final 禁止继承,避免被其他人继承后破坏。所以 String 是不可变的关键都在底层的实现,而不是一个 final。别只被这一个 final 给迷惑了!

也有人讲到了 immutable 和 mutable 原则。其实呢?回答这个问题还是要回到 java 设计 String 的初衷上来。

至于为什么要让 String 设计成不可变的,那是因为安全性。不可变的好处就是为了安全,具体我们下篇文章再说!

参考资料

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » Java 中 String 为什么设计成 final 类?为什么它有“不可变性”?