网站注册地查询,做网站设计的网站,动漫制作专业平台,企业网站公众号剖析equals方法
1、对于Object来说#xff0c;其equals()方法底层实现就是#xff0c;都是比较对象的引用是否相等#xff0c;下为JDK源码。
Object c 1;
Object d 1;
boolean equals c.equals(d);public boolean equals(Object obj) {return (this obj);…剖析equals方法
1、对于Object来说其equals()方法底层实现就是都是比较对象的引用是否相等下为JDK源码。
Object c 1;
Object d 1;
boolean equals c.equals(d);public boolean equals(Object obj) {return (this obj);
}
2、在JDK中其他类中通常会重写equals()方法例如Integer、String源码如下。
Integer会先将Integer对象转换成基础类型int值来比较所以此时就不再是比较两个对象引用是比较两个对象的值是否相等。
Integer a 1;
Integer b 1;
boolean equals a.equals(b);public boolean equals(Object obj) {if (obj instanceof Integer) {return value ((Integer)obj).intValue();}return false;
}Override
public int hashCode() {return Integer.hashCode(value); // 由于 Integer 是不可变类其 hashCode 就是整数值本身。
} String和Integer一样引用比较重写成了值比较了。
String a a;
String b a;
boolean equals a.equals(b);public boolean equals(Object anObject) {if (this anObject) {return true; // 引用相同返回 true引用相同那么值肯定相同了}return (anObject instanceof String aString) (!COMPACT_STRINGS || this.coder aString.coder) StringLatin1.equals(value, aString.value); // equals 为下面的 equals 方法
}IntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {if (value.length other.length) {for (int i 0; i value.length; i) { // 循环每个字符对比本质是值比较if (value[i] ! other[i]) {return false;}}return true;}return false;
}// JDK17
public int hashCode() {int h hash; // 缓存的 hash 值if (h 0 !hashIsZero) {h isLatin1() ? StringLatin1.hashCode(value): StringUTF16.hashCode(value);if (h 0) {hashIsZero true; // 标记 hashCode 为 0 的情况} else {hash h; // 缓存 hashCode}}return h;
}static int hashCode(byte[] value) {int h 0;for (int i 0; i value.length; i) {h 31 * h (value[i] 0xff);}return h;
}static int hashCode(byte[] value) {int h 0;for (int i 0; i value.length; i 2) {h 31 * h getChar(value, i);}return h;
}static char getChar(byte[] val, int index) {return (char) (((val[index] 0xff) 8) | (val[index 1] 0xff));
} JDK17对String的hashcode()方法与早期版本相比进行了优化主要是为了更好地适应 String 的内部存储机制的变化以及性能提升。从 JDK9开始String 使用了一种称为 Compact Strings 的机制。即String 内部不再总是使用 char[] 存储而是根据字符内容选择 byte[] 存储。如果所有字符是 Latin-1单字节字符0~255则使用 byte[]以节省内存。如果有非 Latin-1 字符需要双字节存储则仍使用 UTF-16 编码。
1、hash用于缓存计算过的 hashCode避免重复计算。
2、hashIsZero标志变量处理特殊情况
如果字符串的 hashCode 计算结果为 0会将 hashIsZero 标记为 true防止后续重复计算。区分未计算和计算后结果为 0 的情况。isLatin1()判断字符串是否为 Latin-1 编码。 如果是 Latin-1则调用 StringLatin1.hashCode(value)。 Latin-1 的 hashCodeStringLatin1.hashCode 遍历 byte[] 数组使用与原始实现相同的算法31 为乘数。否则调用 StringUTF16.hashCode(value)。 UTF-16 的 hashCodeStringUTF16.hashCode 遍历 byte[] 数组每两个字节表示一个 char计算哈希值。
JDK17的优点
支持 Compact Strings
根据字符编码选择不同的计算方式提高内存效率和性能。
性能优化
使用 hashIsZero 减少重复计算。针对 Latin-1 和 UTF-16 分开处理减少不必要的判断和操作。
兼容性
虽然内部实现发生了变化但对外部来说行为与早期版本保持一致。
同时上述说了重写equals()方法还需要重写hashCode 方法。 根据 Object 类的规范 如果两个对象根据 equals 方法比较是相等的那么它们的 hashCode 值也必须相等。 原因 如果只重写了 equals 而没有重写 hashCode会导致在使用哈希表如 HashMap 或 HashSet时出现问题因为这些集合依赖于对象的 hashCode 值来确定存储位置。