网站首页 > java教程 正文
1. Java中的不可变字符串
字符串是字符序列。在 Java 中,与其他编程语言类似,字符串是预定义类型的一部分。Java有java.lang.String类,其实例表示字符串。
String类是不可变的类。不可变意味着String一旦创建了实例,就无法更改。
通常,许多敏感信息片段(用户名、密码、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 。
- 上一篇: Java 注解底层原理
- 下一篇: Java类是如何加载的?
猜你喜欢
- 2025-01-12 Java类是如何加载的?
- 2025-01-12 Java 注解底层原理
- 2025-01-12 Java基础概念整理(必备熟记)
- 2025-01-12 Java量与变量的区别
- 2025-01-12 金蝶一面:Java基本数据类型有哪些?包装类型的常量池技术了解么
- 2025-01-12 卧槽!Spring中竟然有12种定义Bean的方法?
- 2025-01-12 Java项目中枚举定义以及使用
- 2025-01-12 常量和变量
- 2025-01-12 自学Java2(保姆级教学)——常量与变量
- 2025-01-12 常量(Constant)
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)