equals()方法与==的区别
- ==:对于基本类型比较的是值,对于引用类型比较的是地址
1 | public static void main(String[] args) { |
在这里解释一下String类型在jvm是怎样存储的
如果使用“”创建String类型,如str1,str2,它会去常量池查找有没有当前我要创建的值,如果有直接将常量池的引用复制给该变量。第一次使用String str1 = “hello”,由于常量池中没有“hello”,它会在常量池中创建,在使用String str2 = “hello”,由于常量池中存在”hello”,str2它会直接引用这个值,所以str1 == str2为true
使用new创建String对象的时候,它回到常量池去查找有没有我要创建的值,如果有则拷贝一份到堆中,将该副本的引用赋值给变量。如果没有,则实例化该对象放到常量池,并且拷贝副本到堆中,将副本的引用复制给变量
如:String str3 = new String(“hello”),常量池创建,拷贝一份到堆中,并副本赋值给str3,String str4 = new String(“hello”),从常量池拷贝一份到堆中,并将副本引用赋值给str4.所有str3 == str4为false
- equals:Object中的方法,在Object中比较的也是两个对象的地址,但是一般情况下,都要重写equals方法,来指定相等的规则。比如String类,重写equsls方法,比较的是String的值,而不是地址。
案例:一个Student类,重写equals方法,如果它的name相等就认为他们是同一个学生。
1 | public class Student { |
eausle的特性
- 自反性:a.equals(a)一定为true
- 对称性: 如果a.equals(b)为true,那么b.equals(a)一定也为true
- 传递性: a.equals(b)为true,b.equals(c)为true,那么a.equals(c)也为true
equals与hashcode
重写equals是否需要重写hashcode?
在api中是建议在重写equals时,我们有必要重写hashcode.
在一些用到hashcode的数据结构存储数据的时候,如hashset,是一定要重写的hashcode的
hashset存放元素的时候存放的是不重复的元素,它存数据的时候会根据元素的hash值和equals方法来判断是否添加,如果两个元素的hash值相同和equals方法返回为true,则认为元素相同,hashset不将它添加进去。这样就会产生一个问题,假设有 student1 = new Student(“zs”,18),student2 = new Student(“zs”,18),hashset在添加这两个对象的时候,只会将一个对象添加进去,但是如果不重写hashcode,hastset会认为这是两个不同的元素并将它添加进去,当我们在从hashset中取出数据的时候会发现取出了两个相同对象,这与hashset的的规则不符合,所以重写equals方需要重写hashcode.
hashset添加元素的判断
1 | if (p.hash == hash && |
案例:一个Student类,重写equals,不重写hashcode,创建两个属性相等的对象,存放到hashset
1 | @Override |
存放到hashset,并输出到控制台
1 | public static void main(String[] args) { |
输出结果