iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java中的String为什么是不可变的
  • 823
分享到

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

2023-06-17 05:06:37 823人浏览 独家记忆
摘要

这篇文章主要介绍“Java中的String为什么是不可变的”,在日常操作中,相信很多人在Java中的String为什么是不可变的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的String为什么是不

这篇文章主要介绍“Java中的String为什么是不可变的”,在日常操作中,相信很多人在Java中的String为什么是不可变的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的String为什么是不可变的”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

什么是不可变对象?

众所周知, 在Java中, String类是不可变的。那么到底什么是不可变的对象呢?  可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括 基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。

区分对象和对象的引用

对于Java初学者, 对于String是不可变对象总是存有疑惑。看下面代码:

String s = "ABCabc";
System.out.println("s = " + s);

s = "123456";
System.out.println("s = " + s);

打印结果为:

s = ABCabc
s = 123456

首先创建一个String对象s,然后让s的值为“ABCabc”, 然后又让s的值为“123456”。  从打印结果可以看出,s的值确实改变了。那么怎么还说String对象是不可变的呢? 其实这里存在一个误区:  s只是一个String对象的引用,并不是对象本身。对象在内存中是一块内存区,成员变量越多,这块内存区占的空间越大。引用只是一个4字节的数据,里面 存放了它所指向的对象的地址,通过这个地址可以访问对象。

也就是说,s只是一个引用,它指向了一个具体的对象,当s=“123456”; 这句代码执行过之后,又创建了一个新的对象“123456”, 而引用s重新指向了这个心的对象,原来的对象“ABCabc”还在内存中存在,并没有改变。内存结构如下图所示:

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

Java和c++的一个不同点是,  在Java中不可能直接操作对象本身,所有的对象都由一个引用指向,必须通过这个引用才能访问对象本身,包括获取成员变量的值,改变对象的成员变量,调用 对象的方法等。而在C++中存在引用,对象和指针三个东西,这三个东西都可以访问对象。其实,Java中的引用和C++中的指针在概念上是相似的,他们都 是存放的对象在内存中的地址值,只是在Java中,引用丧失了部分灵活性,比如Java中的引用不能像C++中的指针那样进行加减运算。

为什么String对象是不可变的?

要理解String的不可变性,首先看一下String类中都有哪些成员变量。 在jdk1.6中,String的成员变量有以下几个:

public final class String     implements java.io.Serializable, Comparable<String>, CharSequence {          private final char value[];           private final int offset;           private final int count;           private int hash; // Default to 0

在JDK1.7中,String类做了一些改动,主要是改变了substring方法执行时的行为,这和本文的主题不相关。JDK1.7中String类的主要成员变量就剩下了两个:

public final class String       implements java.io.Serializable, Comparable<String>, CharSequence {              private final char value[];               private int hash; // Default to 0

由以上的代码可以看出, 在Java中String类其实就是对字符数组的封装。JDK6中,  value是String封装的数组,offset是String在这个value数组中的起始位置,count是String所占的字符的个数。在 JDK7中,只有一个value变量,也就是value中的所有字符都是属于String这个对象的。这个改变不影响本文的讨论。  除此之外还有一个hash成员变量,是该String对象的哈希值的缓存,这个成员变量也和本文的讨论无关。在Java中,数组也是对象(可以参考我之前 的文章java中数组的特性)。 所以value也只是一个引用,它指向一个真正的数组对象。其实执行了String s = “ABCabc”; 这句代码之后,真正的内存布局应该是这样的:

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

value,offset和count这三个变量都是private的,并且没有提供setValue,  setOffset和setCount等公共方法来修改这些值,所以在String类的外部无法修改String。也就是说一旦初始化就不能修改,  并且在String类的外部不能访问这三个成员。此外,value,offset和count这三个变量都是final的, 也就是说在String类内 部,一旦这三个值初始化了, 也不能被改变。所以可以认为String对象是不可变的了。

那么在String中,明明存在一些方法,调用他们可以得到改变后的值。这些方法包括substring, replace, replaceAll, toLowerCase等。例如如下代码:

String a = "ABCabc";   System.out.println("a = " + a);   a = a.replace('A', 'a');   System.out.println("a = " + a);

打印结果为:

a = ABCabc
a = aBCabc

那么a的值看似改变了,其实也是同样的误区。再次说明, a只是一个引用, 不是真正的字符串对象,在调用a.replace(&lsquo;A&rsquo;,  &lsquo;a&rsquo;)时, 方法内部创建了一个新的String对象,并把这个心的对象重新赋给了引用a。String中replace方法的源码可以说明问题:

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

读者可以自己查看其他方法,都是在方法内部重新创建新的String对象,并且返回这个新的对象,原来的对象是不会被改变的。这也是为什么像 replace, substring,toLowerCase等方法都存在返回值的原因。也是为什么像下面这样调用不会改变对象的值:

String ss = "123456";  System.out.println("ss = " + ss);  ss.replace('1', '0');  System.out.println("ss = " + ss);

打印结果:

ss = 123456
ss = 123456

String对象真的不可变吗?

从上文可知String的成员变量是private final 的,也就是初始化之后不可改变。那么在这几个成员中,  value比较特殊,因为他是一个引用变量,而不是真正的对象。value是final修饰的,也就是说final不能再指向其他数组对象,那么我能改变 value指向的数组吗? 比如将数组中的某个位置上的字符变为下划线“_”。  至少在我们自己写的普通代码中不能够做到,因为我们根本不能够访问到这个value引用,更不能通过这个引用去修改数组。

那么用什么方式可以访问私有成员呢? 没错,用反射, 可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。下面是实例代码:

public static void testReflection() throws Exception {      //创建字符串"Hello World", 并赋给引用s     String s = "Hello World";       System.out.println("s = " + s); //Hello World      //获取String类中的value字段     Field valueFieldOfString = String.class.getDeclaredField("value");      //改变value属性的访问权限     valueFieldOfString.setAccessible(true);      //获取s对象上的value属性的值     char[] value = (char[]) valueFieldOfString.get(s);      //改变value所引用的数组中的第5个字符     value[5] = '_';      System.out.println("s = " + s);  //Hello_World }

打印结果为:

s = Hello World
s = Hello_World

在这个过程中,s始终引用的同一个String对象,但是再反射前后,这个String对象发生了变化,  也就是说,通过反射是可以修改所谓的“不可变”对象的。但是一般我们不这么做。这个反射的实例还可以说明一个问题:如果一个对象,他组合的其他对象的状态 是可以改变的,那么这个对象很可能不是不可变对象。例如一个Car对象,它组合了一个Wheel对象,虽然这个Wheel对象声明成了private  final 的,但是这个Wheel对象内部的状态可以改变, 那么就不能很好的保证Car对象不可变。

到此,关于“Java中的String为什么是不可变的”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Java中的String为什么是不可变的

本文链接: https://www.lsjlt.com/news/287350.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java中的String为什么是不可变的
    这篇文章主要介绍“Java中的String为什么是不可变的”,在日常操作中,相信很多人在Java中的String为什么是不可变的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的String为什么是不...
    99+
    2023-06-17
  • 分析Java中为什么String不可变
    目录常量池便利安全引申问题String在Java中的【引用传递】常量池 Java中我们创建String对象有两种基本方法。 String str1 = "zxhtom"; Str...
    99+
    2024-04-02
  • Java中String是不可变的吗
    这篇文章主要介绍“Java中String是不可变的吗”,在日常操作中,相信很多人在Java中String是不可变的吗问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中String是不可变的吗”的疑惑有所...
    99+
    2023-06-27
  • String的不可变是因为Final 吗
    这篇文章主要讲解了“String的不可变是因为Final 吗”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“String的不可变是因为Final 吗”吧!St...
    99+
    2024-04-02
  • Java中的String对象不可改变的特性有哪些
    Java中的String对象不可改变的特性有哪些?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1. String对象不可改变的特性下图显示了如下代码运行的过程:...
    99+
    2023-05-31
    java string ava
  • java中可变参数是什么
    这期内容当中小编将会给大家带来有关java中可变参数是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动性和面向对象的脚本语言,其...
    99+
    2023-06-14
  • python的可变和不可变数据类型是什么
    这篇文章主要讲解了“python的可变和不可变数据类型是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“python的可变和不可变数据类型是什么”吧!不可变数据类型python中不可变数据...
    99+
    2023-06-02
  • java中不同变量的区别是什么
    本篇内容介绍了“java中不同变量的区别是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!区别在类中的位置成员变量:类中,方法外在内存中的...
    99+
    2023-06-30
  • Java可变参数是什么
    这篇文章主要讲解了“Java可变参数是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java可变参数是什么”吧!什么是可变参数?就是方法参数用 Object... args 三个点形式,...
    99+
    2023-06-19
  • PHP中的可变变量是什么意思
    本篇内容主要讲解“PHP中的可变变量是什么意思”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“PHP中的可变变量是什么意思”吧!我们学习了解了这么多关于PHP的知识,今天学习PHP中什么是可变变量...
    99+
    2023-06-20
  • 为什么 NPM 是 Java 索引教程中不可或缺的工具?
    NPM 是一款为 Node.js 设计的包管理工具,它可以帮助开发者更方便地安装、管理和分享代码包。虽然 NPM 最初是为 Node.js 设计的,但是它也被广泛地用于 Java 开发中,成为 Java 索引教程中不可或缺的工具。本文将介绍...
    99+
    2023-07-27
    索引 教程 npm
  • java中的string是什么意思
    Java中的String是字符串的意思,它是一种类类型,代表了一串字符序列,字符串是不可变的,一旦一个字符串被创建,它的值就不能被改变。Java没有内置的字符串类型,而是在标准Java类库中提供了一个String类来创建和操作字符串,在Ja...
    99+
    2023-07-10
  • java中string的概念是什么
    这篇文章主要介绍了java中string的概念是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇java中string的概念是什么文章都会有所收获,下面我们一起来看看吧。在java中,string是字符串的意...
    99+
    2023-07-05
  • Java中需要将字符串设计成不可变的原有是什么
    这篇文章给大家介绍Java中需要将字符串设计成不可变的原有是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。String是Java中一个不可变的类,所以他一旦被实例化就无法被修改。不可变类的实例一旦创建,其成员变量的...
    99+
    2023-05-31
    java 字符串 ava
  • Java中的String 与 new String()有什么不同的地方
    这篇文章给大家介绍Java中的String 与 new String()有什么不同的地方,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java String 和 new String()的区别栈区存引用和基本类型,不能...
    99+
    2023-05-31
    java string new string()
  • 分析JDK中String的存储区与不可变性
    这篇文章主要介绍“分析JDK中String的存储区与不可变性”,在日常操作中,相信很多人在分析JDK中String的存储区与不可变性问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”分析JDK中String的存储...
    99+
    2023-06-02
  • java如何证明字符串是不可变的
    这篇文章主要介绍了java如何证明字符串是不可变的,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。如何证明字符串是不可变的字符串不可变的这个事我曾写过两篇文章,写到最后我都要吐...
    99+
    2023-06-27
  • Numpy算法:为什么在Java编程中使用容器是必不可少的?
    在Java编程中,容器是必不可少的,特别是在使用Numpy算法时。Numpy是一种用于数值计算的Python库,它提供了高效的多维数组操作功能。虽然Numpy是Python库,但Java也可以使用它,这是因为Java有一个名为Jython...
    99+
    2023-10-01
    编程算法 容器 numpy
  • php数组中的元素可不可以是变量
    今天小编给大家分享一下php数组中的元素可不可以是变量的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。PHP数组中的元素可以是...
    99+
    2023-07-02
  • Java中String、StringBuffer、StringBuilder的区别是什么
    本篇内容主要讲解“Java中String、StringBuffer、StringBuilder的区别是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java中String、StringBuf...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作