前些天面试遇到一个非常难的关于String的问题,“String为何被设计为不可变的”?类似的问题也有“String为何被设计为final?”个人认为还是前面一种问法更准确,设计成final仅仅保证了String类不能被继承,而Immutable相对于final要严格的多,关于对Immutable的理解可以参考这里

  下文主要翻译自:http://java67.blogspot.sg/2014/01/why-string-class-has-made-immutable-or-final-java.html

  要回答这个问题,java程序员必须对String是如何工作的,它的特性是什么,还有一些关键原则有一个很深刻的理解。String类在Java里是一个上帝类,它有一些其他类所不具备的特性,比如String字面量存储在常量池,你可以通过操作符“+”来连接多个String。鉴于String类在Java编程里的重要性,Java设计者把它设计为final的,这意味着你不可以继承这个类,同样这也有助于String对象的不可变。
 
  记得在某个地方读到过,有人向Java的创建者James Gosling问过为什么要把String类设计成final,但他在安全性方面作了一些回答。有人认为,使类设计成final严重限制了它的进化或扩展能力,James评论说,把类设计成final是Java安全性承诺的关键因素,这样在Java平台里就没有人可以改变它的行为了。
 
  现在回到标题的问题,Java里String为什么是不可变的呢?首先可以确定的是这么设计是有优势的。现在,让我们思考一下这些优点或特性,这是决定这样设计的原因。

 
  下面列出5个Java里把String设计为final或者Immutable的原因:
  除了JamesGosling关于安全性的提示之外,我认为以下原因也说明了为什么String在Java中设计成final或Immutable的
 
  1)String常量池
java设计者明白String类将会是所有Java应用中使用最多的类,这也是他们想从设计之初就要优化的原因。优化方向的一个关键想法是在String常量池中存储String字面量。目标是通过共享来减少临时字符串对象,为了共享,String类必须是不可变的。你不能在一个彼此不互知的双方之间共享可变对象。让我们以一个假设的例子为例,其中两个引用变量指向同一个字符串对象:
String s1 = "Java";
String s2 = "Java";
  现在假如s1的值被改成“C++”,引用变量s2在它不知道的情况下,他的值也变成了“C++”。但是通过把String设计为不可变,上述的共享String字面量成为了可能。总之,要在Java中实现字符串池的关键思想,必须把String类设计成不可变的。
 
  2) 安全性
  Java在为每个级别的服务提供安全环境方面有着明确的目标,而字符串在整个安全方面是至关重要的。 String已被广泛用作许多Java类的参数,例如,打开网络连接时,可以将主机和端口作为字符串传递,在Java中读取文件时,可以将文件和目录的路径作为字符串传递,打开数据库连接时,可以将数据库URL作为字符串传递。如果字符串不是不可变的,用户可能已经授权访问系统中的特定文件,但是在身份验证之后,他可以更改到其他文件的路径,这可能会导致严重的安全问题。类似地,在连接到数据库或网络中的任何其他机器时,可变字符串值可能会造成安全威胁。可变字符串也可能导致反射中的安全性问题,因为参数是字符串。
 
  3) 字符串在类加载机制中的应用
  另一个使字符串成为最终或不可变的原因是因为它在类加载机制中被大量使用。由于字符串不是不可变的,攻击者可以利用这一事实,将加载标准Java类(例如java.io.Reader)的请求更改为恶意类com.un未知n.DataStolenReader。通过保持字符串的最终性和不可变性,我们至少可以确保JVM正在加载正确的类。
 
  4) 多线程好处
  由于并发性和多线程是Java的关键产品,因此考虑字符串对象的线程安全性是很有意义的。由于预期字符串将被广泛使用,使其不可变意味着没有额外的同步,因此意味着在多个线程之间共享字符串的代码要简单得多。这个单一的特性使得已经很复杂、混乱和容易出错的并发编码变得更加容易。因为字符串是不可变的,而且我们只是在线程之间共享它,所以它会产生更易读的代码。
   

  5) 优化与性能
  现在,当你使类不可变时,您预先知道,这个类一旦创建就不会改变。这保证了许多性能优化的开放思维,例如缓存。字符串本身知道,我不会更改,所以字符串缓存它的hashcode。它甚至延迟计算hashcode,一旦创建,只需缓存它。在简单的世界中,当您第一次调用任何String对象的hashCode()方法时,它计算哈希代码,然后对hashCode()的所有后续调用都返回已经计算的缓存值。这将带来良好的性能增益,因为字符串在基于哈希的映射(例如Hashtable和HashMap)中大量使用。如果不使其不可变,就不可能缓存哈希代码,因为它取决于字符串本身的内容。
 
 
  除了上述优点外,您还可以考虑到在Java中字符串是immutable的优点。它是最流行的对象之一,可用作基于哈希集合的键,例如HashMap和Hashtable。虽然对HashMap键来说,不可变性不是绝对需要的,但使用不可变对象作为键要比使用可变对象安全得多,因为如果可变对象的状态在HashMap中停留期间发生了更改,那么就不可能检索回它,因为它的Eques()和hashCode()方法依赖于已更改的属性。如果一个类是不可变的,那么当它存储在基于哈希的集合中时,就没有改变它的状态的风险,我已经强调的另一个重要的好处是它的线程安全性。由于字符串是不可变的,所以您可以在线程之间安全地共享它,而不必担心额外同步。它使并发代码更具可读性,减少了错误的发生。
  
  尽管有所有这些优点,但不变性也有一些缺点,例如,它并非没有成本。由于字符串是不可变的,因此它会生成大量临时对象和逃逸对象,这会给垃圾收集器带来压力。Java设计者已经考虑过了,将字符串字面量存储在常量池中是他们减少字符串垃圾的解决方案。这确实有帮助,但是你必须小心地创建字符串而不使用构造函数,例如,new String()不会从字符串池中选择对象。而且,平均来说,Java应用程序产生的垃圾太多了。此外,将字符串存储在池中有与其相关的隐藏风险。字符串池位于JavaHeap的PermGen空间中,与JavaHeap相比,这是非常有限的。拥有太多的字符串文字会很快占满这个空间,从而导java.lang.OutOfMemoryError。值得庆幸的是,Java语言设计者已经意识到了这个问题,从Java 7开始,他们将字符串池移动到正常的堆空间,这比PermGen空间要大得多。使字符串成为不可变的还有另一个缺点,因为它限制了它的可扩展性。现在,您不能扩展String来提供更多的功能,虽然很少需要。
 
 
 

java里String类为何被设计为final的更多相关文章

  1. 在java中String类为什么要设计成final?

    大神链接:在java中String类为什么要设计成final? - 程序员 - 知乎 我进行了重新排版,并且更换了其中的一个例子,让我们更好理解. String很多实用的特性,比如说“不可变性”,是工 ...

  2. Java中String类为什么被设计为final?

    Java中String类为什么被设计为final   首先,String是引用类型,也就是每个字符串都是一个String实例.通过源码可以看到String底层维护了一个byte数组:private f ...

  3. 在java中String类为什么要设计成final

    在java中String类为什么要设计成final? - 胖胖的回答 - 知乎 https://www.zhihu.com/question/31345592/answer/114126087

  4. 在Java中String类为什么要设计成final?String真的不可变吗?其他基本类型的包装类也是不可变的吗?

    最近突然被问到String为什么被设计为不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下. 1.String的不可变String类被final修饰,是不可继承和 ...

  5. java中String类为什么要设计成final?

    1 将方法或类声明为final主要目的是:确保它们不会在子类中改变语义.String类是final类,这意味着不允许任何人定义String的子类. String基本约定中最重要的一条是immutabl ...

  6. 【笔记】在java中String类为什么要设计成final?

    部分内容转自知乎:https://www.zhihu.com/question/31345592 从自己的理解进行加工,压缩. String本质上是一个final类 public final clas ...

  7. java中String类为什么不可变?

    在面试中经常遇到这样的问题:1.什么是不可变对象.不可变对象有什么好处.在什么情景下使用它,或者更具体一点,java的String类为什么要设置成不可变类型? 1.不可变对象,顾名思义就是创建后的对象 ...

  8. Java的string类为什么是不可变的

    最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类 ...

  9. Atitit.java c#这类编程语言的设计失败点attilax总结

    Atitit.java c#这类编程语言的设计失败点attilax总结 1. Npe1 2. Api粒度过小而又没有提供最常用模式1 3. checked exception(jeig n jyejy ...

随机推荐

  1. Java-Maven(七):Eclipse中Maven依赖、聚合、继承特性

    之前通过学习了解,maven集成到eclipse中的如何创建项目,以及maven命令插件在eclipse中安装后的用法.那么接下来我们将会学习一些maven在项目中的一些特性,及如何使用. Maven ...

  2. POJ-2993 Emag eht htiw Em Pleh---棋盘模拟

    题目链接: https://vjudge.net/problem/POJ-2993 题目大意: 输入和输出和这里相反. 思路: 模拟题,没啥算法,直接模拟,不过为了代码精简,还是花了一点心思的 #in ...

  3. 如何彻底解决MySQL更改默认字符集以及字符乱码问题!!!

    在我们使用MySQL数据库时,字符乱码,对我们来说是一个很头疼的问题.今天笔者就来教大家如何彻底解决更改默认字符集以及字符乱码问题. 当我们使用压缩包进行MySQL安装后,系统会使用默认的字符集,这时 ...

  4. [LeetCode] Shortest Unsorted Continuous Subarray 最短无序连续子数组

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  5. [LeetCode] Next Greater Element II 下一个较大的元素之二

    Given a circular array (the next element of the last element is the first element of the array), pri ...

  6. 从三个开源项目认识OpenFlow交换机 - OVS

    在SDN/NFV的网络革新技术浪潮的引领下,催生了诸多数据面开源方案的诞生.业界知名度较高的有OVS(Open vSwitch).FD.io (Fast Data I/O).ODP(Open Data ...

  7. 计蒜客NOIP模拟赛4 D1T1 小X的质数

    小 X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小 X 认为,质数是一切自然数起源的地方. 在小 X 的认知里,质数是除了本身和 1以外,没有其他因数的数字. 但由于小 X ...

  8. 【BZOJ1040】【ZJOI2008】骑士

    Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬. 最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战 ...

  9. 洛谷P1856 [USACO5.5]矩形周长Picture

    题目背景 墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 题目描述 编写一个程序计算周长. 如图1所示7个矩形. ...

  10. ●BZOJ 3963 [WF2011]MachineWorks

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3963 题解: 斜率优化DP,CDQ分治. 先按时间排序.(规定以下内容的第i台机器的卖出时间 ...