Java中的String为什么要设计成不可变的?

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

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、

原文地址:https://www.cnblogs.com/wkfvawl/p/11693260.html

时间: 2024-10-06 02:09:47

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

java中的String类 字符串拆分成字符串数组 判定邮箱地址 字符串比较 看结果?

看结果1? package com.swift; class ArrayString { public static void main(String[] args) { String str = "swift:30|sunny:28|Ben:32"; String str1[] = str.split("\\|"); for (int i = 0; i <= str1.length - 1; i++) { String str2[] = str1[i].sp

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

声明:本博客为原创博客,未经同意,不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(原文链接为http://blog.csdn.net/bettarwang/article/details/26744661),看代码和提问.讨论都更方便. Java中final的作用主要表如今三方面:修饰变量.修饰方法和修饰类.以下就从这两个方面来解说final的作用.在文末从final及类的设计安全性出发,论述了Java中String为何要被设计成不可变类. 1.final修饰变量 fina

java中String为什么设计成不可变对象

设计成不可变对象为了安全和高效 1.安全方面:举例说明:在文件操作或反射操作的时候需要传递字符串,如果是设计成可变的那么就会造成安全问题 2.高效:举例说明 字符串源码中会将hashcode缓冲下来,那么比如在HashMap中以字符串为key时第一次计算出hash值放缓冲中,以后直接就可以获取到这个值了,不需要重新计算了 原文地址:https://www.cnblogs.com/wgDream/p/12038838.html

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

在java中,String是字符串常量,可以从内存,同步机制,数据结构等方面分析 1:字符串中常量池的需要 String不同于普通基础变量类型的地方在于对象.java中的字符串对象都保存在字符串常量池中,创建字符串时首先会从这个常量池中查找是否已经存在相同的字符串对象,不存在的情况下才会创建新的字符串对象. 如果字符串被设计成可变的,便存在当修改一个字符串的时候同时影响另一个指向常量池的相同对象(有潜在性风险) 2:HashCode缓存 在HashMap或者HashSet数据结构中,存储Stri

身为大神的你知道为什么Java要把字符串设计成不可变的嘛!

String是Java中一个不可变的类,他一旦被实例化就无法被修改.不可变类的实例一旦创建,其成员变量的值就不能被修改,不可变类有很多优势. 这些大家都知道,那大家知道为什么JAVA的设计者要把它设计成一个不可变的类嘛, 下面讲给大家进行讲解. 字符串池 字符串池是方法区中的一部分特殊存储.当一个字符串被被创建的时候,首先会去这个字符串池中查找,如果找到,直接返回对该字符串的引用. 下面的代码只会在堆中创建一个字符串 String string1 = "abcd"; String st

[转]为什么Java中的String不可变

笔主前言: 众所周知,String是Java的JDK中最重要的基础类之一,在笔主心中的地位已经等同于int.boolean等基础数据类型,是超越了一般Object引用类型的高端大气上档次的存在. 但是稍有研究的人就会发现,String对象是不可修改的,源代码中的String类被定义为final,即为终态,不可继承,String也不提供任何直接修改对象内部值的方法,每次使用replace.substring.trim等方法,或是使用字符串连接符+时,都是返回一个全新的String对象,整个Stri

为什么Java中的String是不可变的?(Why String is immutable o...

There are many reasons due to the string class has been made immutable in Java. These reasons in view, concurrency issues, security issues and performance issues. Here is a list of various valid reasons to go for immutable string class: String在Java中被

读深入理解Java中的String(包括JVM)一文总结和提升

读深入理解Java中的String(包括JVM)一文总结和提升 摘要:String作为Java语言中的字符串模拟类,无论是实际的编程工作还是笔试面试过程,都需要我们都String类非常熟悉,对于String类的大部分字符串操作方法,都必须达到熟练运用的程度才行.但是,笔试和面试过程中,面试官往往喜欢问一些String特性相关的题目,来考察面试者对于String基础知识的掌握是否牢固.(本人尚未研读深入理解JVM这本书,分析JVM都是查看网上资料来分析的,若在接下来的内容有分析不到位的地方请见谅和

Java中的String为什么是不可变的?

转载:http://blog.csdn.net/zhangjg_blog/article/details/18319521 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变. 区分对象和对象的引用 对于J