初学者学Java(十二)
有关String类的一些问题
String类是一个特殊的类,他并不是一个原生数据类型,但我们却可以像给原生数据类型赋值一样的给他赋值。这就导致他有两种创建方式:
1.Stringstr = “Hello World”;
2.Stringstr = new String(“Hello World”);
但是这两种方式的意义是完全不同的,这里面的原因是因为String类有一个特殊的东西:字符串池,英文叫做StringPool.我为什么要强调一下英文呢,因为我发现在阅读帮助文档的时候不一定要认识所有的单词,但关键的几个一定要认识,否则就会很麻烦。
对于第一种创建方式我们一般称作“字面值赋值”。
这种方法创建字符串,他首先会查找 StringPool 中是否存在“Hello World”这个对象,如果不存在,则在 String Pool 中创建一个“HelloWorld”对象,然后将 String Pool 中的这个“HelloWorld”对象的地址返回来,赋给引用变量 str,这样 str 会指向 String Pool 中的这个“HelloWorld”字符串对象,如果存在,则不创建任何对象,直接将 String Pool 中的这个“HelloWorld”对象地址返回来,赋给 str 引用。注意,此时引用变量指向的是字符串池中的对象,而非是堆中的对象。
第二种创建方式就是我们一般创建类对象的方式。
但他会首先在 StringPool 中查找有没有“Hello World”这个字符串对象,如果有,则不在 StringPool中再去创建“Hello World”这个对象了,直接在堆中(heap)中创建一个“HelloWorld”字符串对象,然后将堆中的这个“Hello World”对象的地址返回来,赋给 str引用。注意,此时引用变量指向的是堆的对象,而非是字符串池中的对象。
两种方式的相同点是创建完后在StringPool中一定会有一个以其输入的为内容的字符串对象,不同的是第一种方式引用变量指向的是字符串池中点对象,而第二种方式会在堆中新建一个同内容的对象,然后指向他。
所以,以下代码返回true:
Stringstr1 = “ye jin wei”;
Stringstr2 = “ye jin wei”;
System.out.print(str1== str2);
因为他们指向同一个字符串池中的对象。
而以下代码则返回flase:
Stringstr3 = new String(“ye jin wei”);
Stringstr4 = new String(“ye jin wei”);
System.out.print(str3== str4);
因为他们指向的是堆中不同的对象。虽然对象的内容相同,但引用变量的值是对象的地址。
想要比较第二种内容是否相同,就要用到equal()方法,下面我们来讲一下equals()方法。
public boolean equals(Object anObject)我们先来看一下方法的源码:
public boolean equals(Object anObject) {
if (this== anObject) {
return true;
}
if(anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if(v1[i++] != v2[j++])
returnfalse;
}
return true;
}
}
returnfalse;
}
这个源码还是比较容易懂得,第一个if语句是用来判断输入的引用变量和调用方法的引用变量内存的地址是不是相同,即是不是指向同一个对象,如果指向同一个对象就不用比了,那字符串内容肯定是相同的了。第二个if语句先判断了一下传人的是不是String类的引用,如果不是,那也不用比了,返回flase.然后我们来看底下的while循环。这个循环的作用是将字符串的字母一个一个的进行比较,如果有不一样的就返回flase,如果都一样就返回true.这个方法的原理就是这个样子了,下面我们来讲另一个String类的方法。
public Stringintern();对于这个方法,我的理解是他可以把指向堆中对象的引用变量改为StringPool中同内容的对象,当然堆中的对象并不会消失。
帮助文档是这样写的:
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object)方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
我写了个小程序来验证了一下:
packagetest;
publicclassInternTest {
publicstaticvoidmain(String[] args) {
String str1 = "Hello";
String str2 = new String("Hello");
System.out.println(str1 ==str2);
str2 = str2.intern();
System.out.println(str1 ==str2);
}
}
这个程序的结果是:
flase
true
第一个flase为什么我就不说了。
第二个我说一下,因为变量str1指向的是String Pool中的“Hello”,而虽然str2本来指向的是堆中的一个对象”Hello”,但是调用了intern()方法后,程序就会将池中和他指向对象的内容相同的对象地址返回给str2,也就是str1内的地址。所以返回true.
String就先讲这些,下一讲还会在讲他的一些内容的。