`

为什么String要设计成不可变的?

阅读更多
是一个老生常谈的话题(This is an old yet still popular question). 在Java中将String设计成不可变的是综合考虑到各种因素的结果,想要理解这个问题,需要综合内存,同步,数据结构以及安全等方面的考虑. 在下文中,我将为各种原因做一个小结。

1. 字符串常量池的需要

字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。

如下面的代码所示,将会在堆内存中只创建一个实际String对象.

[java] view plaincopy

    String s1 = "abcd"; 
    String s2 = "abcd"; 

示意图如下所示:

图1

假若字符串对象允许改变,那么将会导致各种逻辑错误,比如改变一个对象会影响到另一个独立对象. 严格来说,这种常量池的思想,是一种优化手段.

请思考: 假若代码如下所示,s1和s2还会指向同一个实际的String对象吗?

[javascript] view plaincopy

    String s1= "ab" + "cd"; 
    String s2= "abc" + "d"; 

也许这个问题违反新手的直觉, 但是考虑到现代编译器会进行常规的优化, 所以他们都会指向常量池中的同一个对象. 或者,你可以用 jd-gui 之类的工具查看一下编译后的class文件.

2. 允许String对象缓存HashCode
Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。

字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码. 在String类的定义中有如下代码:

[javascript] view plaincopy

    private int hash;//用来缓存HashCode 

3. 安全性
String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。

假如有如下的代码:

[javascript] view plaincopy

    boolean connect(string s){ 
        if (!isSecure(s)) {  
    throw new SecurityException();  
    } 
        // 如果在其他地方可以修改String,那么此处就会引起各种预料不到的问题/错误  
        causeProblem(s); 
    } 


总体来说, String不可变的原因包括 设计考虑,效率优化问题,以及安全性这三大方面. 事实上,这也是Java面试中的许多 "为什么" 的答案。
分享到:
评论

相关推荐

    Java中的String为什么是不可变的?-String源

    在Java编程语言中,String类是一个非常特殊且...总的来说,Java中的String设计为不可变对象是出于性能、安全和并发控制的考虑,这种设计在许多场景下都是有利的。理解这一特性对于编写高效、安全的Java代码至关重要。

    浅谈为什么Java里面String类是不可变的

    那么,为什么 Java 语言的设计者要把 String 类型设计成不可变对象呢?下面,我们将深入探讨字符串不可变性的原因和优点。 不可变对象的定义 不可变对象指的是对象创建之后,对象的内部状态以及对象的内存指针地址...

    Java中的String为什么是不可变的共7页.pdf.z

    总之,`String`的不可变性是Java设计的重要部分,它带来了诸多优点,包括线程安全、性能优化、内存管理等。但同时,开发者需要理解其潜在的性能影响,并在必要时选择可变的`StringBuilder`或`StringBuffer`来优化...

    AndyJennifer#Android_Interview#为什么 String 被设计为不可变的1

    这样的话,以后每次想要用到 HashCode 的时候,不需要重新计算,直接返回缓存过的 hash 的值就可以了,因为它不会变,这样可以提高效率,所以这就使得字符

    Java string不可变原理实例解析

    在面试中,了解并能够解释Java中的String为什么是不可变的,是展示对Java内存模型和多线程概念理解的很好方式。阅读《Effective Java》等书籍可以帮助深入理解这一设计决策背后的思考。同时,熟悉字符串操作的最佳...

    Java中的String对象是不可变的吗Java开发Jav

    在Java编程语言中,String对象被认为是不可变的。这个特性是Java设计者为了优化性能、安全性和线程安全性而有意设定的。理解String对象的不可变性对于Java开发者来说至关重要,因为它影响着代码的编写、内存管理和多...

    Java 中的 String对象为什么是不可变的

    在Java编程语言中,String对象被认为是不可变的,这意味着一旦创建了一个String实例,就不能更改它的内容。这种特性是由String类的设计决定的,它对程序员在处理字符串时提供了许多优势和安全保证。 首先,理解什么...

    JAVA不可变类(immutable)机制与String的不可变性(推荐)

    本文将深入探讨不可变类的概念、优点、设计方法以及String类的不可变性。 一、不可变类简介 不可变类的特征是,它们的实例在创建后,其成员变量的值不能被修改。例如,Java中的Integer、Long和String类都是不可变...

    为什么Java要把字符串设计成不可变的

    Java 字符串设计成不可变的原因是多方面的。首先,从内存角度来说,字符串池的存在使得字符串的重复创建可以被避免,从而节省内存空间。其次,从同步角度来说,字符串的不可变性使得其天生就是线程安全的,不需要...

    探索C#之不可变数据类型

    在C#编程语言中,不可变数据类型是一个重要的概念,它涉及到对象的生命周期和状态管理。不可变对象意味着一旦创建并初始化,其值就不能再被...在适当的情况下,利用不可变类型可以为你的程序带来更高效、更安全的设计。

    Java常用类与基础API-String的理解与不可变性

    综上所述,`String` 的不可变性是其设计的核心原则之一。这一特性不仅保证了并发环境下的安全性,还提高了性能,减少了不必要的内存开销。开发者应当充分利用这一特性来编写更高效、更安全的代码。 #### 三、String...

    简单的string类

    首先,`std::string`是C++标准库中的一个类模板,它表示可变长度的字符序列。在声明时,你可以通过构造函数初始化字符串,例如: ```cpp std::string str = "Hello, World!"; ``` 这将创建一个包含"Hello, World!...

    String和string区别以及string详解

    `string`类型是不可变的,这意味着一旦创建了一个`string`对象,就不能更改它的内容。例如: ```csharp string str = "Hello"; str += " World"; // 实际上是创建了新的字符串对象 ``` 在这个例子中,虽然表面上看...

    Java String不可变

    Java中的String类是不可变的,这一特性对Java程序员来说是非常重要的,因为它直接影响到程序的性能、线程安全以及字符串操作的效率。不可变性意味着一旦一个String对象被创建,其内部的字符数组(value)就不能被...

    模拟可变分区算法实现分区与回收

    1. **理解并实现可变分区存储管理系统的基本概念**:掌握如何为不同大小的进程分配内存区域,并处理内存回收过程中的分区合并问题。 2. **学习和应用分区分配算法**:了解并实践最先适应、最优适应以及最坏适应等...

    JAVA精华 String类一旦初始化就不可以改变,而stringbuffer则可以。它用于封装内容可变的字符串。

    这是因为String对象在Java中是不可变的。这意味着每次对String对象进行操作(如拼接或替换字符),都会生成一个新的String对象。例如,`String x="a"+4+"c"` 在编译时等同于 `String x=new StringBuffer().append("a...

    C#_String与string的区别

    ### C#中String与string的区别详解 在C#编程语言中,`String`与`string`两者虽然在表面上看起来...在实际开发中,应根据具体情况选择使用`string`或`String`,并充分利用`String`的不可变性来优化程序性能和资源管理。

Global site tag (gtag.js) - Google Analytics