在Java里面String类型是不可变对象,这一点毫无疑问,那么为什么Java语言的设计者要把String类型设计成不可变对象呢?这是一个值得思考的问题
Java语言的创建者James Gosling,曾经在一次采访中被人问到:什么时候应该使用不可变对象(immutable object),他回答:任何可以使用的时候都会使用。
在这之前,我们先来简单了解一下,什么是不可变对象?
不可变对象指的是在对象创建之后,对象的内部状态以及对象的内存指针地址都不不能被改变。在Java里面final关键字就是用来辅助创建不可变对象的,但需要注意的是,对于基本类型被final修饰后,就彻底变成了不可变对象,而引用类型被final修饰后,仅仅是指针的内存地址不能改变,如果想要变成彻底的不可变类型,要把该对象里面所有的字段都得用final声明,包括嵌套的对象,否则对象的内部状态也是会变化的,这一点需要理解。
ok,下面我们来分析下为什么String是不可变的?
通过String源码可以看到,String类型的底层是由final修饰的char数组存储。
```java
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
........
}
```
String能被设计成不可变类型的一个重要前是因为它是编程语言里面使用频率最高的一种类型。不可变类型带来的好处,体现在四个方面,分别是:缓存,安全,同步和性能。
(一)缓存
在JVM的运行时数据区域里面,有一个专门的字符串常量池用来存储字符串字面量,如下面一段代码:
```
String s1 = "Hello World";
String s2 = "Hello World";
assertThat(s1 == s2).isTrue();
```
s1和s2变量指针的内存地址其实是一样的,也就是说他们代表是同一个对象,这是jvm常量池做的优化,当第一个字面量声明的时候,它的值会被字符串常量池存储,当s2变量声明的时候,jvm发现常量池已经存在该对象,所以就不会再创建一次,而是直接将一样的内存指针赋值给s2变量,从避免了重复创建对象,节省了内存空间。
此外,由于字符串的不可变性,从而可以让其hashCode也被缓存,在Java里面哈希类数据结构如HashMap, HashTable, HashSet其key用的最多的基本都是String类型,如此一来key的hashCode的也可以在第一次调用之后被缓存,之后直接使用无须重新生成,从而间接的提升访问效率。
(二)安全
不可变特性也能够减少了应用程序在运行时间的安全问题,如下面的一段代码:
```
void criticalMethod(String userName) {
// check
if (!check(userName)) {
throw new SecurityException();
}
// query
query(userName);
}
```
在上面的一段代码,在调用这个方法之后,先检查用户名,如果合法才可以继续查询相关数据,如果String可变,那么攻击者就可以在通过check验证之后,再改变查询的用户名,那么就会存在安全风险,而不可变性能够避免和减少这一情况。另一方面,如果String是可变的,那么同时运行的其他线程如果修改这个值,就有可能导致混乱。
(三)同步
由于String类型的不可变性,使得String对象可以安全的在多个线程之间传递和访问,也就是说你在多线程中是不能改变字符串本身的值,而是在堆里面新创建一个字符串然后操作。当然如果没有final修饰,你是可以改变这个变量的引用地址,也就是说你可以把新生成的内存引用覆盖原来的变量引用,但这里仅仅是引用,并不是变量的值。这一点要注意。
(四)性能
性能方面,其实前面已经提到了,比如字符串的常量池节省内存,缓存Hash类以字符串做key数据结构的hashCode,从而提高访问性能等。由于字符串是编程语言里面最广泛使用的数据结构,所以针对字符串的不可变性带来的优势,可以放大到整个运行的应用程序,从而带来应用程序整体的性能提升。
总结:
本文主要介绍了Java语言里面String类型为什么设计成不可变类型,以及分析了不可变类型的带来的主要优势,需要注意的是虽然不可变类型能够带来不少的好处,但并不是说其没有弊端,不可变类型的每一次修改都需要在内存中新生成一个对象,从另一个方面说针对经常变化的对象是不适合使用不可变类型的,这也是为什么Java里面还提供了可修改值的StringBuilder和StringBuffer类,这在实际开发中常常是需要根据具体情况权衡的。
为了方便更好的交流,互助,学习,讨论问题,欢迎加入我们的“攻城师互助学习交流群”微信群,为了保证交流环境,想加入的小伙伴,可关注公众号,然后后台发送关键词微信群,加我微信号,由我拉你进去。
分享到:
相关推荐
主要介绍了为什么Java里面String类是不可变的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
Java String类为什么是不可变的_动力节点Java学院整理,动力节点口口相传的Java黄埔军校
一、什么是Java中的String类? String类是Java中表示字符串的类。它是不可变的,一旦创建了一个字符串对象,就无法修改它。 二、String类和StringBuilder类有什么区别? String类和StringBuilder类的最主要区别在于...
Java中的String为什么是不可变的?—String源码分析Java开发Java经验技巧共6页.pdf.zip
Java中的String对象是不可变的吗Java开发Java经验技巧共4页.pdf.zip
Java中的String为什么是不可变的共7页.pdf.zip
本文主要来介绍一下Java中的不可变对象,以及Java中String类的不可变性,那么为什么Java的String类是不可变对象?让我们一起来分析一下。 答案一: 流行的Java面试题之一是:什么是不可变对象(immutable ...
众所周知, 在Java中, String类是不可变的。那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象是不可变的。不能改变状态的意思是,不能改变对象...
JAVA精华 String类一旦初始化就不可以改变,而stringbuffer则可以。它用于封装内容可变的字符串。它可以使用tostring()转换成string字符串。
主要介绍了Java string不可变原理实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了Java的string类为什么是不可变的,总结了三个答案,需要的朋友可以参考下
String对象是不可变的,但这仅意味着你无法通过调用它的公有方法来改变它的值。本文给大家介绍java中的string对象为什么是不可变的,需要的朋友一起了解了解吧
众所周知, 在Java中, String类是不可变的。那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象是不可变的。不能改变状态的意思是,不能改变对象...
主要介绍了java String不可变的好处,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
动力节点的Java课程适合绝对零基础的观看,教程中讲解了Java开发环境搭建、Java的基础语法、Java的面向对象。每一个知识点都讲解的非常细腻,由浅入深。适合非计算机专业,想转行做Java开发的朋友,或者想让Java基础...
class:java中class确切的表示为一个类 object:java中object确切的表示为一个对象,也称为类的实例 其实,如果一个类被设计...包装类(e.g.Integer或Float)和String类是不可变类的代表。 访问器方法(accesso
主要介绍了JAVA不可变类(immutable)机制与String的不可变性(推荐)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
主要介绍了Java String源码分析并介绍Sting 为什么不可变的相关资料,需要的朋友可以参考下
所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。如JDK内部自带的很多不可变类:Interger、Long和String等。接下来通过本文给大家介绍Java不可变类机制,需要的朋友参考下
Java中的String类是可变的还是不可变的? Java中的equals方法和hashCode方法有什么关系? Java中什么是重载【Overloading】?什么是覆盖【Overriding】?它们有什么区别? Java中什么是多态?如何实现多态? Java中...