专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java 字符串常量池

temp10 2025-01-12 18:32:49 java教程 9 ℃ 0 评论

1. Java中的不可变字符串

字符串是字符序列。在 Java 中,与其他编程语言类似,字符串是预定义类型的一部分。Java有java.lang.String类,其实例表示字符串。

String类是不可变的类。不可变意味着String一旦创建了实例,就无法更改。

Java 字符串常量池

通常,许多敏感信息片段(用户名、密码、URL、端口、数据库、套接字连接)都表示为字符串并传递。通过使此信息不可变,代码可以免受各种安全威胁。

字符串不可变性还允许缓存字符串文本,这允许应用程序使用大量字符串文本,而对堆内存和垃圾回收器的影响最小。

在可变上下文中,修改字符串文本可能会导致变量损坏。

2. 什么是 Java 中的字符串常量池?

Java 中的内存分为三个部分,即堆、堆栈和字符串池。字符串常量池是用于存储字符串文本的特殊区域。

  • 请注意,在 Java 7 之前,字符串池是永久生成内存区域的一部分。
  • 从 Java 7 开始,字符串与应用程序创建的其他对象一起在 Java 堆区域中分配。
  • 后来,在Java 8中,永久生成已被完全删除。

因此,在最新的 JVM 中,字符串池是堆内存中分配用于存储字符串文本的特殊区域。

尽管字符串池已从 Permgen 空间移动到堆内存区域,但围绕字符串创建、文字、对象和实习的所有概念都没有改变。

3. 字符串文本和字符串对象的区别

在 Java 中,字符串文本是使用双引号创建的字符串,而字符串对象是使用new()创建的字符串。请注意,字符串文本是在字符串池区域中创建的,字符串对象是在堆内存区域中创建的。

String strLiteral = "Hello World";

String strObj = new String("Hello World");

假设我们要创建两个内容相同的字符串 “howtodoinjava”。如果内容为 “howtodoinjava” 的字符串已存在,则新文本将指向已存在的文本。对于字符串对象,每次都会在堆中创建一个新的字符串对象。让我们看一个例子:

String a = "howtodoinjava";
String b = "howtodoinjava";

System.out.println(a == b);     //true

在上面的程序中,我们创建了两个具有相同内容的字符串文本。在字符串池中创建“a”后,下一个字符串文本“b”指向内存区域中的同一对象,因此'a == b'是true。

String a = "howtodoinjava";
String b = "howtodoinjava";

System.out.println(a == b);

String c = new String("howtodoinjava");

System.out.println(a == b);     //true
System.out.println(b == c);     //false

在上面的程序中,我们创建了一个具有类似内容的新 String 对象。当我们检查对象引用相等性时,我们会看到b和c指向单独的对象。这意味着当我们创建c字符串对象 ,在内存中创建了一个新对象。

4.String.intern()API

我们知道字符串文本是在字符串池中创建的,字符串对象是在堆内存区域中创建的。

我们可以使用方法 String.intern()为字符串对象创建字符串文字。在字符串对象上调用intern()时,该方法会在堆内存中创建 String 对象的精确副本,并将其存储在 String 常量池中。

String a = "howtodoinjava";
String b = "howtodoinjava";

String c = new String("howtodoinjava");
String d = c.intern();

在上面的示例中,字符串a, b 和d将引用 SCP 中的相同字符串文字。字符串c将继续指向堆中的对象。

5. 优势

5.1. 增强的安全性

如前所述,字符串池允许字符串不可变。不可变对象有助于使应用程序更安全,因为它们可能存储敏感信息。由于我们无法更改不可变的对象,因此有助于使安全性更加有效。

5.2. 线程安全

字符串可能是 Java 应用程序中最常用的对象。想象一下,如果字符串是可变的。在这种情况下,在应用程序中管理线程安全将是一场噩梦。

任何不可变对象本质上都是线程安全的。这意味着多个线程可以共享和操作字符串,而不会有损坏和不一致的风险。

6. 缺点

6.1. 字符串类不能扩展

如果我们想扩展 String 类以添加更多功能,我们就做不到。声明final不可变类以避免扩展性。但幸运的是,我们有许多第三方库(Apache Commons Lang,Spring Framework,Guava),它们为几乎所有用途提供了出色的实用程序类。

6.2. 敏感数据长时间存放在内存中

字符串中的敏感数据(例如,密码)可能会在内存中驻留更长时间(在 SCP 中),因为 SCP 利用垃圾回收器的特殊处理。垃圾回收器访问 SCP 的频率(周期)与其他内存区域不同。

由于这种特殊处理,敏感数据在SCP中保留很长时间,并且容易被不必要的使用。为了避免这个潜在的缺点,建议将敏感数据(例如密码)存储在 char[]中而不是 String 中。

6.3. 可能的内存不足错误

与其他存储区域相比,SCP是一个小的内存区域,可以很快填充。在 SCP 中存储过多字符串文本将导致OutOfMemoryError 。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表