当面试官问道为什么 String 是final的时候,要答出两方面:

答:final意味着不能被继承或者被重写,String类用final修饰是Java的设计人员不希望客户端程序员继承String类,并有可能改写String类中的方法。使用String对象的最佳实践,应该是关联 或者依赖,而不是继承。

第一就是final char value[] 的 final ;
第二就是 final class 的 final。

这两个final都要紧扣安全与性能两个方面阐述。

1、final char value[] 的final 要抓住几个关键点是:value[]数组的final用于 限制字符数组的修改。字符串将会被大量使用,从性能上考虑迫使Java语言的设计者将 char[] 设计为共享的,又因为字符串是共享的再次迫使设计者考虑到线程安全性,这才需要用final来修饰,避免并发场景下的行为不可预测

2、final class 的final 要抓住几个关键点是:类上的final用于限制产生子类(或限制多态/或限制行为的变化)。字符串的使用是频繁的,如果通过多态的方式使用String子类对象及其方法将会一定程度上导致性能下降(多态的实现原理:底层的虚函数表),同时String中的方法也可能面临被Override重写的危险导致程序语义不安全、甚至是逻辑错误,与Java自始至终强调的安全性理念相违背。

.

String为什么要不可变

  • 为什么保证String不可变呢,因为只有当字符串是不可变的字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现,因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。
  • 如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞
  • 因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
  • 因为字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。