资讯专栏INFORMATION COLUMN

Java的String不可变性

atinosun / 625人阅读

摘要:但是通过构造函数的并不是。通过构造函数创建的变量在机制上与其他对象一致,都是在上创建新的对象,然后把引用赋给变量。此外,的方法和等方法实现均是调用了构造函数创建了新的对象,所以他们返回的也都是存在于上的新对象。

String经常在一个语言中或多或少都有些特殊地位。在Java亦不例外。今天先来讨论,String是不可变的。

String是引用类型,String变量储存一个地址,地址指向内存堆中的String对象。当我们说变量不可变,有两种不可变性:

变量储存的地址不可变;

地址指向的对象内容不可变。

String的不可变指的是哪一种?下面用例子来看。

通常有人在疑问String不可变时,会举这样的例子:我们平时不都像下面这样在“修改”String字符串吗:

String s = "hello,world";
s = "Hello,coder";
System.out.println(s);    //Hello,coder

我认为这只是一个语义上的误导。赋值操作符=通常作用于基本数据类型时,确是修改变量的值。所以在这里让人误以为也是修改了变量的内容。但是对于引用类型String,s="Hello,coder"的实际作用是将变量s指向另一个内容为Hello,coder的新的对象。

所以,对于String不可变性的结论显而易见了:String变量指向的地址是可变的,他的不可变性当然说的是第二种——地址指向的对象内容不可变。

纵览String的方法,String类确实没有提供能从String外部修改对象的方法。我们熟悉的replace,substring等等方法都要返回一个String,其实都是在返回一个新的对象,而没有修改原有的对象。

为什么要设计成对象内容不可变?

String常量池

一个说法是便于实现String常量池。String存在于常量池中,当新创建一个字符串变量,如果字符串在内存中已经存在,那么就会把这个已经存在于常量池对象的地址赋给变量。这样可节省内存开销。

但这不完全对。

只有两种情况下创建的String变量,他们才会指向常量池中的同一对象:

String是字面直接量赋值创建。字面直接量是编译期常量,变量会指向常量池中的对象。所有字面量赋值创建的String变量都会指向常量池中的对象。

通过String类的intern()方法得到String变量也是指向常量池中的对象。

但是通过构造函数new String()的并不是。通过构造函数创建的String变量在机制上与其他对象一致,都是在heap上创建新的对象,然后把引用赋给变量。

简单例子验证。

String a = "hello,world";
String b = "hello,world";
boolean c = (a == b);                  //true

String d = new String("hello,world");
String e = new String("hello,world");;
boolean f = (d == e);                  //false

String g = d.intern();
boolean h = (a == g);                 //true

此外,String的方法substring,relpacesplit等方法实现均是调用了构造函数创建了新的对象,所以他们返回的String也都是存在于heap上的新对象。

综上来看似乎节省不了多少内存,毕竟程序中编译常量是少数,大多数String都是在运行时产生。

线程安全

这一点显而易见,对象内容都不可变了,自然不会有线程安全问题。

代码安全

String经常被用来存储server connection, database connection或者file path等等。如果String可变,一旦代码某处改动了字符串,会对系统有安全和稳定性威胁。发生在其他普通字符串,则是不可预料的bug。尤其是代码复杂度很高的时候,一个字符串对象被多个变量引用,直接修改对象内容,引起所有引用该对象的变量都发生变化,容易引起bug。

当然这一点主要是降低程序员的错误和bug的可能。

其实,话说回来,在JAVA里,String不可变也并非特殊,所有包装类Interger,Boolean等都是不可变类。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77028.html

相关文章

  • 记一次愚蠢经历--String不可变性

    摘要:文本已收录至我的仓库,欢迎记录一次在写代码时愚蠢的操作,本文涉及到的知识点不可变性一交代背景我这边有一个系统,提供一个接口去发送短信。 前言 只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 记录一次在写代码时愚蠢的操作,本文涉及到的知识点:String不可变性 一、交代背景 我这边有一个系统,...

    woshicixide 评论0 收藏0
  • String 不可变性

    摘要:的不变性,如下图所示,当你改变了的之后指向了一个新的对象原对象不做改变。但其引用的数组是可变的。所以的不可变性的关键并不是的作用。同时编写者为了避免因为的不可变性导致占用大量空间,为此设计了字符串常量池 在猫眼的面试中被面试官问到为什么String的字符串是不变的。当时我的回答是因为String类是用final关键字修饰的,当被问到为什么用 final修饰就是不可变的时候我发现自己说的...

    sydMobile 评论0 收藏0
  • 第3章:抽象数据类型(ADT)和面向对象编程(OOP) 3.1数据类型和类型检查

    摘要:所有变量的类型在编译时已知在程序运行之前,因此编译器也可以推导出所有表达式的类型。像变量的类型一样,这些声明是重要的文档,对代码读者很有用,并由编译器进行静态检查。对象类型的值对象类型的值是由其类型标记的圆。 大纲 1.编程语言中的数据类型2.静态与动态数据类型3.类型检查4.易变性和不变性5.快照图6.复杂的数据类型:数组和集合7.有用的不可变类型8.空引用9.总结 编程语言中的数据...

    zhangqh 评论0 收藏0
  • Java String类笔记

    摘要:这两个操作符都是编译器默认引入了类,最后都调用方法返回对象,临时对象被回收,因此效率极为低下 Java String类笔记 声明 文章均为本人技术笔记,转载请注明出处https://segmentfault.com/u/yzwall String的不可变性 String的不可变性 // String declaration public final class String ...

    Vicky 评论0 收藏0
  • StringString类型为什么不可

    摘要:性能当字符串是不可变时,字符串常量池才有意义。字符串常量池的出现,可以减少创建相同字面量的字符串,让不同的引用指向池中同一个字符串,为运行时节约很多的堆内存。 在学习Java的过程中,我们会被告知 String 被设计成不可变的类型。为什么 String 会被 Java 开发者有如此特殊的对待?他们的设计意图和设计理念到底是什么?因此,我带着以下三个问题,对 String 进行剖析: ...

    zhiwei 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<