一、不可变类和不可变对象

Normally,you create an object and allow its contents to be changed later.However ,occasionally it is desirable to create an object whose contents cannot be changed once the object has been created.We call such an object as immutable object and its class as immutable class.

创建一个一旦其内容就不能在改变的对象,称其为一个不可变对象(immutable object),而它的类称为不可变类(immutable class)。

JDK中String的源码

public final class String implements Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char[] value; /** Cache the hash code for the string */
private int hash;// Default to 0

可以看到String的本质是一个char数组,是对字符串数组的封装,并且是被final修饰的,创建后不可改变。

二、String类不可变性的好处

1、便于实现字符串池(String pool)

在Java中,由于会大量的使用String常量,如果每一次声明一个String都创建一个String对象,那将会造成极大的空间资源的浪费。Java提出了String pool的概念,在堆中开辟一块存储空间String pool,当初始化一个String变量时,如果该字符串已经存在了,就不会去创建一个新的字符串变量,而是会返回已经存在了的字符串的引用。

String a = "Hello world!";
String b = "Hello world!";

如果字符串是可变的,某一个字符串变量改变了其值,那么其指向的变量的值也会改变,String pool将不能够实现!

2、使多线程安全

看下面这个场景,一个函数appendStr()在不可变的String参数后面加上一段“bbb”后返回。appendSb()负责在可变的StringBuilder后面加"bbb"。

public class test {
// 不可变的String
public static String appendStr(String s) {
s += "bbb";
return s;
} // 可变的StringBuilder
public static StringBuilder appendSb(StringBuilder sb) {
return sb.append("bbb");
} public static void main(String[] args) {
String s = new String("aaa");
String ns = test.appendStr(s);
System.out.println("String aaa>>>" + s.toString());
// StringBuilder做参数
StringBuilder sb = new StringBuilder("aaa");
StringBuilder nsb = test.appendSb(sb);
System.out.println("StringBuilder aaa >>>" + sb.toString());
}
}

如果程序员不小心像上面例子里,直接在传进来的参数上加上“bbb”.因为Java对象参数传的是引用,所有可变的StringBuffer参数就被改变了。可以看到变量sb在Test.appendSb(sb)操作之后,就变成了"aaabbb"。
有的时候这可能不是程序员的本意。所以String不可变的安全性就体现在这里。

在并发场景下,多个线程同时读一个资源,是安全的,不会引发竞争,但对资源进行写操作时是不安全的,不可变对象不能被写,所以保证了多线程的安全。

The
advantage of immutability comes with concurrency. It is difficult to
maintain correctness in mutable objects, as multiple threads could be
trying to change the state of the same object, leading to some threads
seeing a different state of the same object, depending on the timing of
the reads and writes to the said object.
By having an immutable
object, one can ensure that all threads that are looking at the object
will be seeing the same state, as the state of an immutable object will
not change.

3、避免安全问题

在网络连接和数据库连接中字符串常常作为参数,例如,网络连接地址URL,文件路径path,反射机制所需要的String参数。其不可变性可以保证连接的安全性。如果字符串是可变的,黑客就有可能改变字符串指向对象的值,那么会引起很严重的安全问题。

因为String是不可变的,所以它的值是不可改变的。但由于String不可变,也就没有任何方式能修改字符串的值,每一次修改都将产生新的字符串,如果使用char[]来保存密码,仍然能够将其中所有的元素设置为空和清零,也不会被放入字符串缓存池中,用字符串数组来保存密码会更好。

4、加快字符串处理速度

由于String是不可变的,保证了hashcode的唯一性,于是在创建对象时其hashcode就可以放心的缓存了,不需要重新计算。这也就是Map喜欢将String作为Key的原因,处理速度要快过其它的键对象。所以HashMap中的键往往都使用String。

在String类的定义中有如下代码:

private int hash;//用来缓存HashCode

总体来说,String不可变的原因要包括 设计考虑,效率优化,以及安全性这三大方面。

https://blog.csdn.net/jiahao1186/article/details/81150912

https://blog.csdn.net/u012546526/article/details/44458185

https://blog.csdn.net/hyddhy/article/details/87105691

https://www.cnblogs.com/wcyBlog/p/4073725.html、

Java中的String为什么要设计成不可变的?的更多相关文章

  1. String类为什么设计成不可变的

    在Java中将String设计成不可变的是综合考虑到各种因素的结果,需要综合考虑内存.同步.数据结构以安全方面的考虑. String被设计成不可变的主要目的是为了安全和高效. 1)字符串常量池的需要 ...

  2. 看结果,测试?java中的String类 字符串拆分成字符串数组 判定邮箱地址 字符串比较 参数传递?

    看结果1? package com.swift; class ArrayString { public static void main(String[] args) { String str = & ...

  3. Java 中的 String 真的是不可变吗?

    我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class String implements java.io.Seriali ...

  4. String的内存模型,为什么String被设计成不可变的

    String是Java中最常用的类,是不可变的(Immutable), 那么String是如何实现Immutable呢,String为什么要设计成不可变呢? 前言 关于String,收集一波基础,来源 ...

  5. 深刻理解Java中final的作用(一):从final的作用剖析String被设计成不可变类的深层原因

    声明:本博客为原创博客,未经同意,不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(原文链接为http://blog.csdn.net/bettarwang/article/det ...

  6. 为什么Java中的String是设计成不可变的?(Why String is immutable in java)

    There are many reasons due to the string class has been made immutable in Java. These reasons in vie ...

  7. Java为什么把String设计成不可变的(immutable)

    在java中,String是字符串常量,可以从内存,同步机制,数据结构等方面分析 1:字符串中常量池的需要 String不同于普通基础变量类型的地方在于对象.java中的字符串对象都保存在字符串常量池 ...

  8. 为什么String要设计成不可变的?

    英文原:http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/ 转自:http://blog.csdn.net/ren ...

  9. JAVA中的String类(详解)

    Java.lang.String类是final类型的,因此不可以继承这个类.不能修改这个类.String是一个类不属于基本数据类型. 可以从源码中看到,String是一个final类型. String ...

随机推荐

  1. 重学前端--js是面向对象还是基于对象?

    重学前端-面向对象 跟着winter老师一起,重新认识前端的知识框架 js面向对象或基于对象编程 以前感觉这两个在本质上没有什么区别,面向对象和基于对象都是对一个抽象的对象拥有一系列的行为和状态,本质 ...

  2. 阿里云如何基于标准 K8s 打造边缘计算云原生基础设施

    作者 | 黄玉奇(徙远)  阿里巴巴高级技术专家 关注"阿里巴巴云原生"公众号,回复关键词 1219 即可下载本文 PPT 及实操演示视频. 导读:伴随 5G.IoT 的发展,边缘 ...

  3. 牛客练习赛36 A Rabbit的字符串(字符串最小表示法)

    链接:https://ac.nowcoder.com/acm/contest/328/A来源:牛客网 题目描述 Rabbit得到了一个字符串,她的好朋友xxx可以给这个字符串施加一次魔法. 魔法可以选 ...

  4. django基础之day04知识点----查询相关

    from django.test import TestCase # Create your tests here. ''' 当你想单独测试django中某一个py文件时,你需要手动配置测试文件 在m ...

  5. Table实现表头固定 内容滚动

    <div style="width: 800px;"> <div class="table-head"> <table> & ...

  6. 【玩转SpringBoot】让错误处理重新由web服务器接管

    其实web服务器是会处理错误的 在web.xml还是随处可见的年代时(确实有点老黄历了),下面的这些配置应该都不陌生. 根据错误代码处理错误,如下图01: 根据异常类型处理错误,如下图02: 不过我们 ...

  7. javascript中引用传递的问题如何解决

    我们有时候会向一个方法中传入一个参数,并且对这个参数做一些处理的操作: 但是因为是引用传递,处理过后会对原有的对象造成修改,无法进行反复使用. 如例子: 两次打印的结果一模一样.这样下一个方法在继续使 ...

  8. VMware kali虚拟机环境配置

    编译内核 (1)执行命令uname -r以查看内核版本. (2)执行命令apt-cache search linux-headers查看是否安装内核头文件. (3)  如果uname -r出现的内容在 ...

  9. Bash脚本编程之算术运算

    简介 Bash所支持的算术运算和C语言是一样的,这里指的是操作符(operator)以及它们的优先级(precedence).结合性(associativity)和值,详见Shell Arithmet ...

  10. C语言程序设计100例之(25):确定进制

    例25    确定进制 问题描述 6*9 = 42 对于十进制来说是错误的,但是对于13进制来说是正确的.即 6(13)* 9(13)= 42(13),因为,在十三进制中,42 = 4 * 13 + ...