关于String的一些问题
This is a hidden message
1
String str=new String("abc");
对于这行代码,常见的问题一般是这行代码一共创建了几个对象?
1 | String str="abc"; |
而对于这行代码,大家的答案一定很明确,是2个;
接下来我们就从这一道题展开,来回顾下关于创建String对象的一些知识。
对于上面的代码,我们可以把它分成四个部分:String str
,=
,"abc"
以及new String()
String str
显然只是在栈中创建了名为str
的变量,他并没有创建对象;
=
是对变量str
进行赋值,将某个对象的引用指向它,也没有创建对象;
之后就剩下new String("abc")
了,那我们为什么要将他分为"abc"
以及new String()
呢,让我们接着看。
1 | public String(String original) { ...} |
让我们重新回到代码,看看String构造器是什么样的。
众所周知,我们常用的创建对象的方式有以下两种:
- 使用
new
创建对象; - 调用
Class
类的newInstance
方法,利用反射机制创建对象。
我们正是使用new
关键字调用了String
类的构造方法创建了一个对象,并将它的引用赋值给了str
变量。
但是仔细看String
类的构造方法,这个构造方法的参数也是一个String
对象,而这个对象在我们的代码中就是"abc"
。
这里,我们就要引入另一种创建String对象的方式,也就是引号内文本。这种方式是String
特有的,并且它与new的方式存在很大区别。
让我们看看下面的三个例子分别创建了一个对象:
1 | String str="abc"; |
毫无疑问,这行代码创建了一个对象;
1 | String a="abc"; |
那这段代码呢?答案是两个;
1 | String a="ab"+"cd"; |
再看看这里呢?答案是三个。
说到这里,我们就要引入下字符串常量池的知识了。
JAVA虚拟机(JVM)为了提升性能和减少内存开销,避免字符的重复创建,其维护了一块特殊的内存空间,即字符串池,当需要使用字符串时,先去字符串池中查看该字符串是否已经存在,如果存在,则可以直接使用,如果不存在,初始化,并将该字符串放入字符串常量池中。
我们先来看看第一行代码String str="abc";
背后是如何执行的,JVM首先会在字符串池中寻找是否存在与"abc"
对象相同的对象,它的判断方式是String
的equals
方法;如果存在,则不再创建新对象,直接将已有对象的引用赋值给str
;如果不存在,则现在字符串池中创建这个对象,然后将它的引用赋值给str
。看到这里,你一定也知道了第二个例子的答案为什么是一个了。
可以看出,只有用双引号包裹字符串的方式(或者采用两个引号字符串拼接的方式)创建的String
对象才会放入字符串池;而对于所有用new方式创建的String
对象,他们只会被放到堆当中,并不会放到字符串池中。因此,推荐大家使用引号包裹文本的方式来创建String
对象以提高运行效率,而实际上我们在编程中也习惯这么做。
关于String的一些问题