首先看下final关键字修饰类的作用:被final修饰的类不可被继承,由此,这个问题就变成了,为什么官方不允许继承String
我们先看下官方对String类的注释的一点说明
Strings are constant; their values cannot be changed after they are created
大意为:字符串是常量,他们的值在被创建以后不能够被修改。
说到这里,我们先看下最常见的字符串对象的创建方式
String str1 = "abc";String str2 = new String("abc")//读者可以思考下以上两种方式的却别
上面两种创建String对象的区别在于:
- 前者不会在堆中生成实例对象,而会在常量池中产生一个字符串常量
- 后者会在堆成生成一个String类型的实例,不会在常量池中产生字符串常量
从图中也能看出两种方式的区别
从上图中可以直观的看出同样是创建String,前者比后者更节省内存,因为使用了常量池技术,而实现常量池,就必须保证字符串不可变。假设有两个String对象分别指向常量池中的同一个字符串“abc”,如果第三个字符串改变了这个常量池的字符串,那势必会导致前两个String对象的值发生变化,进而导致程序异常。
读者可以思考一个问题:假设让你实现一个常量池,字符串可变,能实现么?
讲到这里,String类被定义成final的第一个原因大家应该都比较清楚了,我们继续分析,在JDK当中,不仅仅String类被定义成final,Integer、Long、Double等基本的包装类型都被定义成final,为什么这些基础的类型都被定义成final了呢,这里我认为最根本的一个原因在于:安全
JVM虚拟机无论再怎么跨平台,讲到底,还是基于在操作系统上实现的,这些所谓String对象,Integer对象在堆内存当中,对于操作系统而言也无非是一块内存数据,如果有一些开发者继承String对象,通过内部方法调用获取到其他String对象的信息,那会导致信息泄露,举个例子,你通过String在内存中存储了密码,我继承一个String类,获取你的密码,那这样就会有极大的安全隐患。
总结下,为什么String类被定义成final?
- 为了实现常量池,节省内存
- 为了安全
如果大家有不同意见,欢迎评论