==的比较
1、若是直接比较的是八大基本数据类型,则比较的是他们的值
String str1 = "aaa";
String str2 = "aaa";
System.out.println(str1 == str2);
int a = 1;
int b = 2;
System.out.println(a == b);
Integer c = 3;
Integer d = 3;
System.out.println(c == d);
结果是:
true
false
true
2、若是比较的是对象,则是比较的是两个对象的内存地址
public class Demo2 {
public static void main(String[] args) {
String str1 = new String("aaa");
String str2 = new String("aaa");
System.out.println(str1 == str2);
Integer c = new Integer(3);
Integer d = new Integer(3);
System.out.println(c == d);
User user1 = new User(1,"李四");
User user2 = new User(1,"李四");
System.out.println(user1 == user2);
}
}
class User{
private int id;
private String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
false
false
false
equals()的比较
public class Demo3 {
public static void main(String[] args) {
String str1 = "a";
String str2 = "a";
System.out.println(str1.equals(str2));
Integer a = new Integer(1);
Integer b = new Integer(1);
System.out.println(a.equals(b));
String str3 = new String("abc");
String str4 = new String("abc");
System.out.println(str3.equals(str4));
Date date = new Date();
Date date1 = new Date();
System.out.println(date.equals(date1));
Student student1 = new Student(1,"张三");
Student student2 = new Student(1,"张三");
System.out.println(student1.equals(student2));
}
}
class Student{
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
结果:
true
true
true
true
false
结果分析:
使用equals()进行比较的无非就是字符串之间的比较或者对象之间的比较,由于字符串和八大基本数据类型的包装类日期类等还有一些其他类,重写了equals()方法,所以比较的规则会发生变化,看人家的源码
以下是Object中的equals方法,我们都知道,Object类是所有类的根类,所以若没有重写Object中的这个equals方法,则可以认为两个对象之间比较的是内存地址,所以 Student student1 = new Student(1,“张三”);和Student student2 = new Student(1,“张三”);虽然这两个对象的id和姓名一模一样,但是没有重写equals方法,底层还是用的==比较的是对象的内存地址,所以返回的是false
public boolean equals(Object obj) {
return (this == obj);
}
一般情况下重写了equals方法也要重写HashCode方法
HashCode官方文档解释:
返回对象的哈希码值。 支持这种方法是为了散列表,如HashMap提供的那样 。
hashCode的总合同是:
只要在执行Java应用程序时多次在同一个对象上调用该方法, hashCode方法必须始终返回相同的整数,前提是修改了对象中equals比较中的信息。 该整数不需要从一个应用程序的执行到相同应用程序的另一个执行保持一致。
如果根据equals(Object)方法两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。
不要求如果两个对象根据equals(java.lang.Object)方法不相等,那么在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果。 但是,程序员应该意识到,为不等对象生成不同的整数结果可能会提高哈希表的性能。
尽可能多的合理实用,由类别Object定义的hashCode方法确实为不同对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但Java的编程语言不需要此实现技术。)
当然字符串肯定也重写了HashCode方法:如下重写后的HashCode方法可以知道,同一个字符串的话,拥有同一个var[],根据 h = 31 * h + val[i];计算返回的Hash值肯定也相等;
可以简单理解为HashCode就是按照一定的规则将与对象相关的信息,比如内存地址、属性等,映射成一个数值,这个数值称为散列值,也就是说俩个不同的对象他们的HashCode值可能相等,但是两个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;
}
以下是字符串重写的equals() 我们先了解一下字符串的存储特点,JDK1.8中JVM把String常量池移入了堆中,同时取消了“永久代”,改用元空间代替(Metaspace)
java中对String对象特殊对待,所以在堆区域分成了两块,一块是字符串常量池(String constant pool),用于存储java字符串常量对象,另一块用于存储普通对象及字符串对象。
所以当比较str1 = “a”,和str2 = "a”,时,他两都存在字符串常量池中,所以当调用重写后的equals方法时,会判断str1和str2都是指向同一个位置的a所以判断 if (this == anObject) { return true;},结果返回true、 当比较 str3和str4的时候,这是两个字符串对象的比较 ,所以 if(anObject instanceof String)条件成立,看判断体内容我们会发现,其实比较两个字符串对象是否相等是把两个字符串对象的内容拆分成两个字符数组,然后再一个一个遍历进行比较,若有,有一个字符不相等,则直接返回false , if (v1[i] != v2[i])return false;,若都相等则才返回true,所以String str3 = new String(“abc”);和String str3 = new String(“abc”);是相等的.
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;
}
以下是int 的包装类Integer重写后的equals()方法:看代码可以知道,当调用两个Integer调用这个重写后的equals的时候,底层会先判断是否是Integer对象,如果是则直接用比较两个值的大小是否相等,若相等,直接返回true就行,所以 Integer a = new Integer(1);和
Integer b = new Integer(1);equals比较返回的是true,同理其他的基本数据类型的包装类的重写后的比较规则大同小异,直接去看他们重写后的equals就可知道比较规则。
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}