字符串的比较
谈到字符串的比较,我不得不介绍equals方法
如果我们用equals方法从原码可以看出,比较的则是字符串的内容
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
但我们用==直接比较,则是比较的变量名中的地址
下面我们来看看字符串在java中是如何创建的:
字符串的"=="比较
首先先介绍一下字符串的存储
形如"hello"这种叫做常量字符串
1.常量字符串定义后不能更改
2.这种常量字符串储存在堆区中字符串常量池中
情况1:
public class Stringlei {
public static void main(String[] args) {
String str1="hello";
//str1为引用类型 储存了hello字符串的地址
String str2 = new String("hello");
String str3 = new String("hello").intern();
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//true
str2.intern();
System.out.println(str2 == str1);//false
}
}
上图可以看出:
1.由于str1是直接被"hello"字符串赋值的,所以str1直接指向字符串常量池
2.str2是在堆区new了一个”hello“,所以在堆区开辟了一个val间接指向已经存在的"hello"字符串
3.str3用了inter()方法并且赋值给str3,就会将池中的引用给引用变量
4.可以看到最后str2.intern()后并没有与str1相等是因为并没有赋值,并且池中就有**"hello"字符串**,所以这种情况并不入池,所以str2并没有改变
情况二:
public class Stringlei {
public static void main(String[] args) {
String str2=new String("he")+new String("llo");
str2.intern();//intern并未赋值
String str1="hello";
System.out.println(str1==str2);//true
}
}
可以看到在这种情况下str1竟然等于了str2,那这又是为什么呢?
首先在堆区开辟指向字符串常量池中"he",“llo”(同时将二者放入字符串池)的空间
然后在堆区开辟字符串“hello”,其地址给str2,然后此时池中并没有"hello",让str2.intern()后,就会把**"hello"的引用入池,最后把池中的引用给str1**
可以总结出intern()方法特点:
如果方法没赋值:
1.池中没有该字符串
把引用入池
2.池中有该字符串
则不入池
如果方法赋值
常量池有就会把引用给这个变量
情况三:
public class Stringlei {
public static void main(String[] args) {
String str1="hello";
String str2 = "he"+"llo";
System.out.println(str1==str2);//true
String str3 = "he"+new String("llo");
System.out.println(str1==str3);//false
}
}
1.由于str2由两个常量字符串拼接而成,在编译过程中,自动转化成"hello",所以str2等于str1
2.而str3是先在堆区开辟指向字符串常量池中"llo"的空间,将其与池中"he"拼接成新的字符串在堆区重新开辟,并把地址给str3