当前位置:网站首页>String为什么不可变?
String为什么不可变?
2022-07-31 02:13:00 【likelong965】
String为什么不可变?
什么是不可变?
一个对象创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。
不能改变状态是指:不能改变对象内的成员变量,包括基本数据类型值不能改变,引用数据类型引用不能改变,引用指向的对象的状态也不能改变。
String为什么是不可变的?
这就要看jdk源码了,String源码如下:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
...
}
下面来解读一下,首先String类被final修饰,表明String类无法被继承,其次String底层核心字符数组char value[]也是由final修饰。final修饰的字段创建以后就不可改变。数组是引用数据类型,数组value不可变只是单纯的引用地址无法被改变,但是引用地址指向的数组对象是可变的。
数组变量只是stack上的一个引用,数组的本体结构在heap堆。String类里的value用final修饰,只是说stack里的这个叫value的引用地址不可变。没有说堆里数组本身数据不可变。
如下代码示例:
final int[] value = {
1,2,3};
value[2] = 100; //这时候数组里已经是{1,2,100},而且代码并不会报错
那么String类到底为什么是不可变的呢?
原因如下:
①String由final修饰禁止继承,避免被其他人继承后破坏。②字符数组是由private和final共同修饰,final修饰表明数组引用无法被改变;private修饰表明字符数组只能在String类里使用,而且所有String的方法都没有去改变数组元素。
因此String是不可变的关键都在底层的实现,而不是一个final了得。
为什么 String 被设计成不可变的?
1、字符串常量池优化需要
字符串常量池是方法区的一个特殊的储存区。当新建一个字符串的时候,如果此字符串在常量池中早已存在,会返回一个已经存在字符串的引用,而不是新建一个对象。
如下代码只会在堆中创建唯一一个字符串对象。
String string1 = "abcd";
String string2 = "abcd";
内存图是这样的:

如果String可变,那么用某个引用一旦改变了字符串的值将会导致其他引用指向错误的值。
2、缓存哈希码
字符串的哈希码在 Java 中经常使用。例如,在 HashMap 或 HashSet 中。字符串不可变保证哈希码始终相同,所以在操作的时候可以不必担心哈希码的改变。这意味着每次使用哈希码时都无需计算。这样效率更高。这也是HashMap中的key往往都使用字符串的原因。
在 String 类中,它具有以下代码:
private int hash;//this is used to cache hash code.
3、使其他对象使用更加方便
为了使其具体化,请考虑以下程序:
HashSet<String> set = new HashSet<String>();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));
for(String a: set)
a.value = "a";
在此示例中,如果 String 是可变的,则可以更改其值,这将违反 set 的设计(set 包含不重复的元素)。当然,上面的例子只是为了演示,String类中并没有value属性。
4、出于安全考虑
像网络地址URL,文件路径path以及用户账号密码等通常都是以字符串String类型保存,如果字符串是可变的,将会引发各种安全隐患。
比如将密码用String类型保存,那么它将一直留在内存中,直到垃圾收集器把它清除。假如String类是可变的,那么这个密码可能会被改变,导致出现安全问题。
5、线程安全
同一个字符串实例可以被多个线程共享,因为字符串不可变,本身就是线程安全的。
总之,String出于效率和安全原因,它被设计为不可变的。
参考资料:
1、https://blog.csdn.net/weixin_38004638/article/details/115012897
2、https://www.programcreek.com/2013/04/why-string-is-immutable-in-java/
边栏推荐
- AI在医疗影像设备全流程应用
- Inter-vlan routing + static routing + NAT (PAT + static NAT) comprehensive experiment
- 加密生活,Web3 项目合伙人的一天
- Likou Daily Question - Day 46 - 704. Binary Search
- Face detection based on opencv
- CV-Model [3]: MobileNet v2
- 【Bank Series Phase 1】People's Bank of China
- 基于FPGA的图像实时采集
- 二层广播风暴(产生原因+判断+解决)
- Layer 2 broadcast storm (cause + judgment + solution)
猜你喜欢

Are you still working hard on the limit of MySQL paging?

Observer mode (1)

ShardingJDBC usage summary

Face detection based on opencv

Path and the largest

What have I experienced to become a tester who is harder than development?

Detailed explanation of STP election (step + case)

leetcode-952: Calculate max component size by common factor

CV-Model【3】:MobileNet v2

系统需求多变如何设计
随机推荐
General introduction to the Unity interface
mysql view
静态路由+PAT+静态NAT(讲解+实验)
The effective square of the test (one question of the day 7/29)
My first understanding of MySql, and the basic syntax of DDL and DML and DQL in sql statements
[Map and Set] LeetCode & Niu Ke exercise
Introduction to flask series 】 【 flask - using SQLAlchemy
【银行系列第一期】中国人民银行
Refuse to work overtime, a productivity tool set developed by programmers
Fiddler captures packets to simulate weak network environment testing
Static routing + PAT + static NAT (explanation + experiment)
曼城推出可检测情绪的智能围巾,把球迷给整迷惑了
验证整数输入
tcp框架需要解决的问题
静态路由解析(最长掩码匹配原则+主备路由)
医疗影像领域AI软件开发流程
After reading "MySQL Database Advanced Practice" (SQL Xiao Xuzhu)
Drools basic introduction, introductory case, basic syntax
[WeChat applet] This article takes you to understand data binding, event binding, event parameter transfer, and data synchronization
934. The Shortest Bridge