必知必会:String不可变的3个好处

2023-11-03 17:11:58 浏览数 (1)

将程序视点设为星标精品文章第一时间阅读

大家好,欢迎来到程序视点!我是小二哥。今天我们来来聊聊String类型对象不可变的问题。

前言

String是Java中一个不可变的类,所以String对象一旦被实例化就无法被修改。我们知道Java中就是这样定义的。但是,为什么要这样设计呢?

String 类设计成不可变的原因及好处?

什么是不可变对象

从字面意思也能够理解,也就是我们的创建的对象不可改变。即,不可变类的实例一旦创建,其成员变量的值就不能被修改。为了实现创建的对象不可变,java语言要求我们需要遵守以下5条规则:

(1)类内部所有的字段都是final修饰的。 (2)类内部所有的字段都是私有的,也就是被private修饰。 (3)类不能够被集成和拓展。 (4)类不能够对外提供哪些能够修改内部状态的方法,setter方法也不行。 (5)类内部的字段如果是引用,也就是说可以指向可变对象,那我们程序员不能获取这个引用。

如果我们查看 String 类的源码,我们会发现它全部满足上面这5个规则。

代码语言:javascript复制
/**(3)*/
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** (1)(2)*/
    private final char value[];

    /**(1)(2)*/
    private int hash; // Default to 0
    ......
    /**(4)(5) 没有setter和getter*/
}
原因及好处

String 设计成不可变,主要是从性能和安全两方面考虑。

性能优化,主要体现在字符串常量池的设计和使用上。

字符串常量池(String pool)是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串已经存在于常量池中,则不会创建新的对象,而是直接引用已经存在的对象。这样做能够减少 JVM 的内存开销,提高效率。

代码语言:javascript复制
String s1 = "abc";
String s2 = "abc";

比如引用 s1和 s2 都是指向常量池的同一个对象 "abc",如果 String 是可变类,引用 s1 对 String 对象的修改,会直接导致引用 s2 获取错误的值。

其次是允许String对象缓存HashCode

String字符串不可变,所以在它创建的时候 hashcode就固定了,且被缓存了起来,之后不需要重新计算。这就使得字符串很适合作为 HashMap 中的 key,效率大大提高。

代码语言:javascript复制
private int hash;//this is used to cache hash code.

大家在 String 类的源码中能看到这个成员变量。把String实例设计为不可变的,那么该实例的成员变量hash也是不会变的。

再者就是安全性上的考虑我们常用 String 字符串在其他Java类中充当参数,比如网络连接地址URL,文件路径path等。假若String不是固定不变的,将会引起各种安全隐患,例如,你本想访问百度,结果输入“www.baidu.com”后变成了你银行卡的转账地址;就问你心里慌不慌

0 人点赞