为什么 String 在 Java 中是不可变的或 final?
字符串在 Java 中是不可变的,因为 String
对象缓存在 String 池中。 由于缓存的字符串文字在多个客户端之间共享,因此始终存在风险,即一个客户端的操作会影响所有其他客户端。 例如,如果一个客户端将字符串“Test”的值更改为“TEST”,所有其他客户端也将看到该值,如第一个示例中所述。 由于 String 对象的缓存出于性能原因很重要,因此通过使 String 类不可变来避免这种风险。 同时,String 被确定为 final,这样就没有人可以通过扩展和覆盖行为来破坏 String 类的不变性,如不可变性、缓存、哈希码计算等。 String 类不可变的另一个原因可能是由于 HashMap
。
由于字符串作为 HashMap
键非常流行,因此对它们来说不可变很重要,这样它们才能检索存储在 HashMap
中的值对象。 由于 HashMap 的工作原理是散列,因此需要相同的值才能正常运行。 如果 String 的内容在插入后被修改,可变的 String 将在插入和检索时产生两个不同的哈希码,可能会丢失 map 中的值对象。
字符串是Java中非常非常特殊的类。 我还没有见过一个不使用 String 编写的 Java 程序。 这就是为什么对 String 的扎实理解对于 Java 开发人员来说非常重要。
String 作为数据类型、传输对象和中介的重要性和流行度也使其在 Java 面试中经常被问到。 为什么 String 在 Java 中是不可变的是 Java 中最常见的字符串面试问题之一,它首先讨论什么是 String,Java 中的 String 与 C 和 C++ 中的 String 有何不同,然后转向什么是 Java 中的不可变对象,不可变对象的好处是什么,为什么要使用它们以及应该在哪些场景中使用它们。 这个问题有时也会问,为什么 String 在 Java 中是 final。
为什么 String 在 Java 中是 Final?
正如我所说,这个问题可能有很多可能的答案,而 String
类的唯一设计者可以自信地回答它。 我认为以下两个原因可以解释为什么 String 类在 Java 中是不可变的或 Final
:
1.字符串池
想象一下没有使字符串不可变的字符串池设施,这根本不可能,因为在字符串池的情况下,一个字符串对象/文字例如 “Test”已被许多引用变量引用,因此如果其中任何一个更改值,其他变量将自动受到影响,即
String A = "Test"
String B = "Test"
现在调用字符串 B,“Test”.toUpperCase()
将同一对象更改为“TEST”,因此 A 也将是“TEST”,这是不可取的。 这是一个很好的图表,显示了如何在堆内存和字符串文字池中创建字符串文字。
2. 安全
字符串已被广泛用作许多 Java 类的参数,例如用于打开网络连接,我们可以将主机名和端口号作为字符串传递,可以将数据库 URL 作为字符串传递以打开数据库连接,我们可以通过以下方式在 Java 中打开任何文件 将文件名作为参数传递给文件 I/O
类。
如果 String 不是不可变的,这将导致严重的安全威胁,我的意思是某人可以访问他有权访问的任何文件,然后可以有意或无意地更改文件名并获得对该文件的访问权限。
由于不变性,我们无需担心那种威胁。 这个原因也与为什么 String 类在 Java 中是 final
密切相关,通过将 java.lang.String
设为 final
,Java 设计者确保没有人会覆盖 String 类的任何行为。
3.线程安全
由于 String 是不可变的,它可以在许多线程之间安全地共享,这对于多线程编程和避免 Java 中的任何同步问题非常重要,不可变性还使 String 实例在 Java 中是线程安全的,这意味着您不需要在外部同步 String 操作 . String还有一个需要注意的地方就是SubString引起的内存泄漏,这不是线程相关的问题,但是需要注意。
4.缓存
String
在 Java 中不可变的另一个原因是允许 String 缓存其哈希码,在 Java 中是不可变的 String 缓存了它的 hashcode,不会每次调用 String 的 hashcode
方法时都计算,这使得它作为 hashmap key 在Java中hashmap中使用非常快。
简而言之,因为 String 是不可变的,一旦创建就没有人可以更改它的内容,这保证了 String 的 hashCode 在多次调用时是相同的。
5.类加载
为什么
String
在 Java 中不可变的另一个很好的理由是:String 不可变的绝对最重要的原因是它被类加载机制使用,因此具有深刻和基本的安全方面。
如果 String 是可变的,则加载 java.io.Writer
的请求可能已更改为加载 mil.vogoon.DiskErasingWriter
简而言之,安全性和字符串池是使字符串不可变的主要原因,我相信还有一些更有说服力的理由,请将这些理由告诉给我们。
相关文章
在 Java 中获取文件大小
发布时间:2023/05/01 浏览次数:139 分类:Java
-
Java 提供了不同的方法来获取文件的字节大小。 本教程演示了在 Java 中获取文件大小的不同方法。使用 Java IO 的文件类获取文件大小 Java IO 包的 File 类提供了以字节为单位获取文件大小的功能。
Java 中的文件分隔符
发布时间:2023/05/01 浏览次数:108 分类:Java
-
本篇文章介绍了 Java 中的文件分隔符。Java 中的文件分隔符 文件分隔符是用来分隔目录的字符; 例如,Unix 使用 /,Windows 使用 \ 作为文件分隔符。
Java 中的文件过滤器
发布时间:2023/05/01 浏览次数:193 分类:Java
-
本篇文章介绍如何在 Java 中使用 FileFilter。FileFilter 用于过滤具有特定扩展名的文件。 Java内置包IO和Apache Commons IO为FileFilter提供了类和接口来进行文件过滤操作。
Java 获取 ISO 8601 格式的当前时间戳
发布时间:2023/05/01 浏览次数:132 分类:Java
-
本篇文章介绍了 ISO 8601 日期格式、其重要性及其在 Java 中的使用。 它还列出了一些优点来强调为什么应该使用 ISO 格式来表示日期。
在 Java 中获取数组的子集
发布时间:2023/05/01 浏览次数:142 分类:Java
-
本篇文章介绍了几种在 Java 中获取数组子集的方法。使用 Arrays.copyOf() 方法获取数组的子集 使用 Arrays.copyOfRange() 方法获取数组的子集
用 Java 填充二维数组
发布时间:2023/05/01 浏览次数:110 分类:Java
-
二维数组是基于表结构的,即行和列,填充二维数组不能通过简单的添加到数组操作来完成。 本篇文章介绍如何在 Java 中填充二维数组。
计算 Java 数组中的重复元素
发布时间:2023/05/01 浏览次数:202 分类:Java
-
本篇文章介绍Java计算数组中重复元素的方法。计算 Java 数组中的重复元素。我们可以创建一个程序来计算数组中的重复元素。 该数组可以是未排序的,也可以是已排序的。
Java 中 List 和 Arraylist 的区别
发布时间:2023/05/01 浏览次数:90 分类:Java
-
表示为单个单元的一组单个对象称为集合。 在 Java 中,Collection 是一个具有多个已定义接口和类的框架,用于将一组对象表示为一个单元。 它允许我们操纵