摘要:但是通过构造函数的并不是。通过构造函数创建的变量在机制上与其他对象一致,都是在上创建新的对象,然后把引用赋给变量。此外,的方法和等方法实现均是调用了构造函数创建了新的对象,所以他们返回的也都是存在于上的新对象。
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,relpace和split等方法实现均是调用了构造函数创建了新的对象,所以他们返回的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
摘要:文本已收录至我的仓库,欢迎记录一次在写代码时愚蠢的操作,本文涉及到的知识点不可变性一交代背景我这边有一个系统,提供一个接口去发送短信。 前言 只有光头才能变强。文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 记录一次在写代码时愚蠢的操作,本文涉及到的知识点:String不可变性 一、交代背景 我这边有一个系统,...
摘要:的不变性,如下图所示,当你改变了的之后指向了一个新的对象原对象不做改变。但其引用的数组是可变的。所以的不可变性的关键并不是的作用。同时编写者为了避免因为的不可变性导致占用大量空间,为此设计了字符串常量池 在猫眼的面试中被面试官问到为什么String的字符串是不变的。当时我的回答是因为String类是用final关键字修饰的,当被问到为什么用 final修饰就是不可变的时候我发现自己说的...
摘要:所有变量的类型在编译时已知在程序运行之前,因此编译器也可以推导出所有表达式的类型。像变量的类型一样,这些声明是重要的文档,对代码读者很有用,并由编译器进行静态检查。对象类型的值对象类型的值是由其类型标记的圆。 大纲 1.编程语言中的数据类型2.静态与动态数据类型3.类型检查4.易变性和不变性5.快照图6.复杂的数据类型:数组和集合7.有用的不可变类型8.空引用9.总结 编程语言中的数据...
摘要:这两个操作符都是编译器默认引入了类,最后都调用方法返回对象,临时对象被回收,因此效率极为低下 Java String类笔记 声明 文章均为本人技术笔记,转载请注明出处https://segmentfault.com/u/yzwall String的不可变性 String的不可变性 // String declaration public final class String ...
摘要:性能当字符串是不可变时,字符串常量池才有意义。字符串常量池的出现,可以减少创建相同字面量的字符串,让不同的引用指向池中同一个字符串,为运行时节约很多的堆内存。 在学习Java的过程中,我们会被告知 String 被设计成不可变的类型。为什么 String 会被 Java 开发者有如此特殊的对待?他们的设计意图和设计理念到底是什么?因此,我带着以下三个问题,对 String 进行剖析: ...
阅读 824·2023-04-26 00:11
阅读 2618·2021-11-04 16:13
阅读 2079·2021-09-09 09:33
阅读 1455·2021-08-20 09:35
阅读 3799·2021-08-09 13:42
阅读 3586·2019-08-30 15:55
阅读 989·2019-08-30 15:55
阅读 2200·2019-08-30 13:55