关于String的一些问题

关于String的一些问题

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
2
String a="abc"; 
String b="abc";

那这段代码呢?答案是两个;

1
String a="ab"+"cd";

再看看这里呢?答案是三个。

说到这里,我们就要引入下字符串常量池的知识了。

JAVA虚拟机(JVM)为了提升性能和减少内存开销,避免字符的重复创建,其维护了一块特殊的内存空间,即字符串池,当需要使用字符串时,先去字符串池中查看该字符串是否已经存在,如果存在,则可以直接使用,如果不存在,初始化,并将该字符串放入字符串常量池中。

我们先来看看第一行代码String str="abc";背后是如何执行的,JVM首先会在字符串池中寻找是否存在与"abc"对象相同的对象,它的判断方式是Stringequals方法;如果存在,则不再创建新对象,直接将已有对象的引用赋值给str;如果不存在,则现在字符串池中创建这个对象,然后将它的引用赋值给str。看到这里,你一定也知道了第二个例子的答案为什么是一个了。

可以看出,只有用双引号包裹字符串的方式(或者采用两个引号字符串拼接的方式)创建的String对象才会放入字符串池;而对于所有用new方式创建的String对象,他们只会被放到堆当中,并不会放到字符串池中。因此,推荐大家使用引号包裹文本的方式来创建String对象以提高运行效率,而实际上我们在编程中也习惯这么做。

作者

ero

发布于

2022-03-23

更新于

2022-06-11

许可协议

评论