1.首先,'==' 大家都很熟悉就是比较地址,话不多说直接上代码 :
public class Demo {
public static void main(String[] args){
String s1 = "123";
String s2 = "123";
String s3 = new String("123");
System.out.println(s1==s2);//输出 true
System.out.println(s3==s1);//输出 false
}
}
上述代码,
首先简单了解一下栈 和 常量池:
1>.栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中)。
2>.常量池:存放字符串常量和基本类型常量( public static final ,java存放字符串用 public final 修饰的value数组 )
s1,s2都是常量,其后面的 "123" 都被放在常量池中,其实在 s2 创建的时候,只是把已经在常量池中的 "123"赋值给了s1引用变量,这样s1当然等于s2啦,因为两者是一个东西,当然地址也相同。
至于s3为什么不等于s1,那是因为,s3是new出来的,也就是说s3new出来的对象在堆中,s3这个引用变量在栈中,但是s1的对象在常量池中,这两个当然地址不一样啦!
2. equals方法
1>.首先上未经重写的equals源码,也就是Object中的 equals 方法:
public boolean equals(Object obj) {
return (this == obj);
}
上述代码,大家不难看出,要比较两个引用变量所指对象的地址。
2>.接下来,上String类型重写过后的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 先比较两个字符串的地址是否相同,如果相同,那么就直接返回true;
接下来,如果地址不相同,那么分别获取两个字符串对应的 char 数组,进行遍历比较每个字符是否相等,如果有一个不相等就返回false,否则就返回true。
注意:java已经将大部分类都重写了equals方法!!! 只有少部分不需要用到equals的,才没重写。
3.hashcode() 方法
写这个之前,我先说一下我之前遇到的一个小问题:
public class Demo {
public static void main(String[] args){
String a= null;
System.out.println(a.hashCode());
}
}
这段代码报错
Exception in thread "main" java.lang.NullPointerException
at ttms.Demo.main(Demo.java:6)
之后我找到了String类重写的 hashCode() 的源码:
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
上述代码中会调用 value.length变量,value就是你的字符串转换成的字符数组,那么问题就简单了,你传进去的对象就是空的,那就肯定没有length属性啦,也就会报空指针异常。
补充一下:如果没有重写hashcode方法,那么就返回的是对象的32位jvm内存地址。