String是一个非可变类(immutable)。
什么是非可变类呢?简单说来,非可变类的实例是不能被修改的,每个实例中包含的信息都必须在该实例创建的时候就提供出来,并且在对象的整个生存周期内固定不变。
好了,知道String是非可变类以后,我们可以进一步了解String的构造方式了。创建一个Stirng对象,主要就有以下两种方式:
String str1 = new String("abc");
Stirng str2 = "abc";
虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。
对于第一种,jvm会马上在heap(堆)中创建一个String对象,然后将该对象的引用返回给用户。
对于第二种,jvm首先会在内部维护的strings pool(我称之为字符串对象池,以下我简称之为 对象池)中通过String的 equels 方法查找是对象池中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法。
看下面的例子:
public class str {
public static void main(String[] args) {
//在堆上创建一个“abc”对象,但是jvm不会主动把该对象引用放到strings pool,
//而equels比较字符串呢,是要到strings pool 里面来做比较的!
String str1 = new String("abc");
//jvm 先在对象池中查找是否有“abc”对象,如果没有则在堆中创建一个“abc”对象,并把引用放到对象池中
String str2 = "abc";
//这个时候 堆中有两个"abc"对象
if (str1 == str2)
System.out.println("str1 == str2");
else
System.out.println("str1 != str2");
}
}
这里为什么不用equels而用==呢?
其实equels是用来比较两个字符串是否相同而已,无论字符串是否是同一个对象,都会返回true,只要是相同就OK了。而"=="则是既要看是否相同,还要看是否同一个对象才能返回true,否则返回false;这就是为什么我们有时候写程序用"=="不能判断字符串而用equels。当然对于理解String比较深的人而言就不存在这个问题了。老师教我们的比较字符串都用equels不要用"==".
我想"=="就相当于数学上比较两个三角形是否全等
equels则是比较两个三角形是否相似;
打印结果是 str1 != str2,因为它们是堆上两个不同的对象
再看例子
//此时,jvm发现strings pool中已有“abc”对象了,因为"abc"equels("abc")
//因此直接返回str2指向的对象给str3,也就是说str2和str3是指向同一个对象的引用
public class str {
public static void main(String[] args) {
// 在堆上创建一个“abc”对象,但是jvm不会主动把该对象引用放到strings pool,
// 而equels比较字符串呢,是要到strings pool 里面来做比较的!
String str1 = new String("abc");
// jvm 先在对象池中查找是否有“abc”对象,如果没有则在堆中创建一个“abc”对象,并把引用放到对象池中
String str2 = "abc";
// 这个时候 堆中有两个"abc"对象
if (str1 == str2)
System.out.println("str1 == str2");
else
System.out.println("str1 != str2");
// jvm 又是先在对象池中查找是否有“abc”对象,一看,哦哦,有这个对象,于是就直接将“abc”的str2引用改成str3
String str3 = "abc";
if (str2 == str3)
System.out.println("str2 == str3");
else
System.out.println("str2 != str3");
//打印结果是 str2 == str3
}
}
//打印结果为 str2 == str3
再看下面的例子:
public class str {
public static void main(String[] args) {
// 在堆上创建一个“abc”对象,但是jvm不会主动把该对象引用放到strings pool,
// 而equels比较字符串呢,是要到strings pool 里面来做比较的!
String str1 = new String("abc");
//这个方法就是将引用放到对象池中
str1 = str1.intern();
// jvm 先在对象池中查找是否有“abc”对象,如果没有则在堆中创建一个“abc”对象,并把引用放到对象池中
String str2 = "abc";
// 这个时候,因为上面str1调用了intern方法,对象池中有了str1对“abc”的引用 此时堆中有只有一个"abc"对象
if (str1 == str2)
System.out.println("str1 == str2");
else
System.out.println("str1 != str2");
// jvm 又是先在对象池中查找是否有“abc”对象,一看,哦哦,有这个对象,于是就直接将“abc”的str2引用改成str3
String str3 = "abc";
if (str2 == str3)
System.out.println("str2 == str3");
else
System.out.println("str2 != str3");
//打印结果是 str2 == str3
}
}
//打印结果是 str1 == str2
附件,本文中的测试程序