两种常见字符串对象创建方式的比较

创建String对象的方法最常见的有两种:

1.使用String对象的构造器显示创建。如:String str=new String("Hello");

2.通过字符串常量直接给String类型变量赋值隐式创建。例如:String str="Hello";

两种形式来创建,第一种是用new()来创建对象的,它会存放在堆中,每调用一次就会创建一个新的对象;而第二种是先在栈中创建一个对String类的对象引用变量str ,然后查找常量池中有没有"abc",如果没有,则创建一个新的对象放入常量池,并令str 指向"Hello",如果已经有"Hello",则直接令str 指向"Hello"

Java程序运行时,引用变量和基本类型的变量都是存放在栈中。而引用变量指向的对象则放在堆中。此外,类、方法、接口中的常量以及字符串常量都是存放在常量池中。

常量池存放的是指在编译器被确定,并被保存已编译的.class文件中的一些数据。

String str="abc";  

毫无疑问,这行代码创建了一个String对象。  

String a="abc";  String b="abc";   那这里呢?Java会确保每个字符串常量只有一个,不会产生多个副本。

答案还是一个。  

String a="ab"+"cd";   再看看这里呢?当一个字符串是由多个字符串常量连接而成时,它本身也是字符串常量。

答案是一个。(JDK5之前,这条语句实际生成了三个字符串常量,包括"ab"、"cd"和"abcd",JDK5之后,编译器做了优化,最终只有一个字符串常量"abcd"存入常量池)

此时若有String b="abcd";那么a==b结果为true

说到这里,我们就需要引入对字符串池相关知识的回顾了。  

在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。由于String类是final的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来程序的混乱。字符串池由String类维护,我们可以调用intern()方法来访问字符串池。  

我们再回头看看String a="abc";,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。因此,我们不难理解前面三个例子中头两个例子为什么是这个答案了。

对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,对此我们不再赘述。因此我们提倡大家用引号包含文本的方式来创建String对象以提高效率,实际上这也是我们在编程中常采用的。

一个很经典的问题:String a=new String("Hello");问创建了几个对象?

答案是2个。

对于"Hello"这个字符串字面量,编译时决定创建一个对象(如果之前常量池中没有创建过这个对象),最后放在常量池中。另一个new关键字调用构造器,是运行时创建存放在堆里面的。两个都是"Hello"。

posted @ 2016-05-24 00:06  skip_2_my_lou  阅读(1482)  评论(0编辑  收藏  举报