这是我参与新手入门的第3篇文章
前言
首先,先来和大家看一道熟悉的面试题,判断以下输出的结果分别是什么?
1 | java复制代码public class Test { |
相信聪明的小伙伴们一定都知道正确输出是什么,没错,结果就是你们想的那样
1 | java复制代码true |
至于原因,因为equals比较的是两个对象的内容是否相等,显而易见,上面4个的内容都是hello
,所以结果都是true
。
而==比较的则是对象的地址是否一致,我们知道,第一种方式String str1 = "hello"
,此种创建方式下,编译器首先检查常量池中是否含有此字符串常量,没有则创建,然后JVM会开辟一块堆内存存放一个隐式对象指向该字符串常量,接着在栈空间里创建str1变量,str1变量指向该块堆内存首地址。
第二种方式String str3 = new String("hello")
,此种创建方式下,直接在堆内存new一个对象,并在常量池中创建“hello”字符串,该对象指向常量池中的“hello”字符串,然后创建str3变量,并将str3变量指向该块堆内存首地址。所以其实它们在内存中的分布是这样的
相信大家看到这里对上面的面试题应该就能理解了,接下来我们再聊聊String这个类的一些特性。
不可变?
打开String类的源码,可以看到这样一句话
这里已经明确说明,String类一旦创建就不会改变,原因也很简单,因为类被final修饰了
再来看下面一段代码
1 | java复制代码public class Test { |
此时输出的结果是HelloWorld
,等等,不是刚说了String类是final修饰的,是不可变的么?怎么刚说完就又能变了呢?其实此段代码执行时,首先在内存中分配一块空间,它的大小为a1和a2空间大小之和,然后将a1和a2的内容复制到该内存空间相应位置,最后将变量a1指向该内存空间,此时的a1其实已经是一个新的String对象了。我们在阅读String中的方法是可以看出,所有的改变字符串的方法其实都是返回了一个新的对象return new String
。
原因
那么问题来了,为什么String会被设计成不可变的呢?主要原因有如下几点:
- 在Java程序中String类型是使用最多的,这就牵扯到大量的增删改查,每次增删改差之前其实jvm需要检查一下这个String对象的安全性,就是通过hashcode,当设计成不可变对象时候,就保证了每次增删改查的hashcode的唯一性,也就可以放心的操作。
- 网络连接地址URL,文件路径path通常情况下都是以String类型保存, 假若String不是固定不变的,将会引起各种安全隐患。就好比我们的密码不能以String的类型保存,,如果你将密码以明文的形式保存成字符串,那么它将一直留在内存中,直到垃圾收集器把它清除。而由于字符串被放在字符串缓冲池中以方便重复使用,所以它就可能在内存中被保留很长时间,而这将导致安全隐患
- 字符串值是被保留在常量池中的,也就是说假若字符串对象允许改变,那么将会导致各种逻辑错误。
本文转载自: 掘金