Java中hashCode与equals原理疑惑:同参对象为何不相等?
为什么String和自定义Person类的equals/hashCode表现不同?
嘿,这个问题刚好戳中了Java中equals()和hashCode()方法的核心逻辑,我来给你一步步理清楚~
先看String类的表现:为什么内容相同就会equals为true、hashCode一致?
Java的String类主动重写了Object类的equals()和hashCode()方法:
equals()方法:不再比较对象的引用地址,而是逐字符对比两个字符串的内容,只要内容完全一致就返回true;hashCode()方法:是根据字符串的字符序列(比如"foo"的每个字符的ASCII值)通过固定算法计算出来的,所以内容相同的String,不管是不是用new创建的不同实例,哈希值必然相同。
这就是为什么你用new String("foo")创建的s1和s2,会得到相同的hashCode和true的equals结果。
再看你的Person类:为什么同参数实例却equals为false、hashCode不同?
你的自定义Person类没有重写equals()和hashCode(),这时候会直接使用父类Object的默认实现:
Object.equals():默认比较的是对象的内存引用地址,也就是判断两个对象是不是同一个实例。你用new Person(...)创建了p1和p2两个独立的对象,它们在内存中的地址不一样,所以返回false;Object.hashCode():默认返回的是和对象内存地址相关的数值(不同JVM实现细节有差异,但核心是区分不同实例),所以两个不同的Person实例,哈希值自然不同。
怎么让Person类实现和String一样的行为?
只需要重写equals()和hashCode()方法,并且遵循Java的规范:如果两个对象equals()返回true,它们的hashCode()必须相等;如果hashCode()不等,equals()必须返回false。
修改后的Person类代码如下:
import java.util.Objects; public class YourClassName { public static class Person { public String name; public String lastName; public Person(String name, String lastName) { this.name = name; this.lastName = lastName; } @Override public boolean equals(Object o) { // 引用相同直接返回true if (this == o) return true; // 传入对象为null或者类型不同,返回false if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; // 比较name和lastName的内容(用Objects.equals避免空指针) return Objects.equals(name, person.name) && Objects.equals(lastName, person.lastName); } @Override public int hashCode() { // 根据name和lastName计算哈希值 return Objects.hash(name, lastName); } } public static void main(String[] args) { String s1 = new String("foo"); String s2 = new String("foo"); System.out.println("String1 hashcode: " + s1.hashCode()); System.out.println("String2 hashcode: " + s2.hashCode()); System.out.println("Is String1 equal to String2?: " + s1.equals(s2)); Person p1 = new Person("John", "Doe"); Person p2 = new Person("John", "Doe"); System.out.println("Person1 hashcode: " + p1.hashCode()); System.out.println("Person2 hashcode: " + p2.hashCode()); System.out.println("Is Person1 equal to Person2?: " + p1.equals(p2)); } }
修改后再运行,你会得到和String一样的结果:p1和p2的hashCode相同,equals()返回true。
额外提醒
如果以后你要把自定义类的对象放进哈希集合(比如HashMap、HashSet),必须重写equals()和hashCode(),否则集合会把内容相同的对象当成不同元素,导致数据重复或者查找失效。
内容的提问来源于stack exchange,提问作者s-kaczmarek
相关产品推荐
相关产品推荐

