关于“==”
如果是原始类型,就是直接比较他们的值;
如果是引用类型,比较的就是引用的值。引用的值就是指对象的地址。也就是两个引用指向同一个对象,那么==比较返回true,否则false。
这里需要说明的一个问题是,关于Integer类中一个看起来奇怪的现象。
看int的包装类型Integer类:
Integer a = 20;
Integer b = 20;
Integer c = 200;
Integer d = 200;
int e = 200;
System.out.println(a == b);
System.out.println(c == d);
System.out.println(d == e);
输出结果:
true
false
true
原来在Integer类的valueOf方法中默认缓存了-128到127之间的数字。而且在Integer与int进行比较的时候会进行自动拆箱操作,也就是比较他们的数字值。
/**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
*
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
我们可以在JVM启动时设置参数-Djava.lang.Integer.IntegerCache.high=1000来间接设置IntegerCache。high的值,或者通过设置-XX:AutoBoxCacheMax=<size>。那么对于其他原始类型的包装类,是否有同样的情况呢。经过研究发现,这些类型的valueOf方法实现如下:
- Boolean的两个值true和false都是缓存在内存中的,无需做任何改造,自己new出来的则是另外一个堆内存。
- Byte的256个值全部是缓存在内存中的,自己new出来的则是另外一个堆内存。
- Short和Long两种类型的缓存范围为-128-127,无法调整缓存范围,在实际场景中需要开发者可以根据需要自己做缓存。
- Float,Double没有缓存,在实际场景中需要开发者可以根据需要自己做缓存。
关于equals()方法
equals()方法首先在Object类中提供了默认实现:
public boolean equals(Object obj) {
return (this == obj);
}
如果不去重写equals()方法,并且在父类列表中都没有重写过equals()方法,那么equals()方法默认就是比较对象地址。一般equals()方法是希望子类去重写的,以实现对比值的功能。
JDK8中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;
}
-
首先判定对比的对象和当前对象地址。如果相同直接返回true;
-
如果不相同,判定出入对象是否为String,若不是直接返回false;
- 如果为String类型,判断字符串长度,若不一致直接返回false;
- 如果长度相同,循环对比两个字符串的char[]数组。逐个对比字符是否相同,若存在不一致的情况就返回false。
关于hashCode()方法
一般equals()方法是与hashCode()方法成对出现的。hashCode()方法提供了对象的hashCode值,是一个native方法:它的返回值默认是与System.identityHashCode(obj)方法相同。注意,它的值绝对不是代表对象的地址。
public native int hashCode();
hashCode只能说是标志对象,这样在hash算法中可以将对象相对离散开,这样就可以在查找数据时根据key快速缩小范围。但我们不能说hashCode值一定是唯一的(不同对象实例可能有相同的hashCode值,这个很好理解,子类可以重写hashCode()方法,当然有可能导致这个结果。)。因此在hash算法应用中在定位到具体链表后,需要进一步循环链表,然后通过equals方法来对比一下key值是否一样。
前面说到hashCode()方法是可以重写的,重写后的方法将决定它在hash相关数据结构中分布情况,通常我们尽可能将对象相对离散开。
下面看看JDK8中String类的hashCode()方法:
/**
* Returns a hash code for this string. The hash code for a
* {@code String} object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using {@code int} arithmetic, where {@code s[i]} is the
* <i>i</i>th character of the string, {@code n} is the length of
* the string, and {@code ^} indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
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;
}
从注释中我们知道String对象的hashCode计算算法为:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
其中s[i]为字符串中对应位置字符,n为字符串长度。这个hashCode是根据char[]数组计算出来的,不同的String完全可以算出相同的hashCode值。因此即使hashCode值一样,也不能证明两个String是一样的。还需要再次遍历char[]数组对比一次才能证明两个对象是否一样。
分享到:
相关推荐
在 Java 中,Object 类提供了两个重要的方法:equals 方法和 hashCode 方法。这两个方法都是用于比较两个对象是否相等的,但它们的实现机理和作用域却有所不同。 equals 方法是用于比较两个对象是否相同的。它的...
Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.
"Java中equals、hashcode和==的区别" Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个...
在Java编程语言中,`equals()` 和 `hashCode()` 方法是对象的基本组成部分,它们在很多场景下都发挥着至关重要的作用。这两个方法与对象的相等性比较和哈希表(如HashMap、HashSet)的运作紧密相关。这篇博客将深入...
在Java编程语言中,`equals()`和`hashCode()`方法是对象的基本组成部分,它们主要用于对象的比较和存储。这两个方法在`java.lang.Object`类中定义,因此所有的Java类都默认继承了这两个方法。然而,根据具体的应用...
本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...
总的来说,理解并正确地重写 `equals()` 和 `hashCode()` 方法是Java编程中的基础技能,它有助于确保对象的比较和集合操作的正确性。在开发过程中,要时刻注意这两个方法的正确实现,以提高代码质量和可维护性。
深入解析Java对象的equals()和hashCode()的使用 在Java语言中,equals()和hashCode()两个函数的使用是紧密配合的,你要是自己设计其中一个,就要设计另外一个。在多数情况下,这两个函数是不用考虑的,直接使用它们...
在Java编程语言中,`equals()`方法和`hashCode()`方法是两个非常重要的概念,它们主要用于对象的比较和哈希表的高效运作。本解析将深入探讨这两个方法的用途、实现原理以及它们之间的关联。 首先,`equals()`方法是...
在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...
在Java编程语言中,`equals()`和`hashCode()`方法是两个至关重要的概念,它们与对象的比较和哈希表操作紧密相关。理解这两个方法的工作原理及其契约是成为一名熟练的Java开发者所必需的。 首先,`equals()`方法是...
Java中的equals()和hashCode()方法详解 Java中的equals()和hashCode()方法是两个重要的方法,它们都是从Object类中继承过来的。equals()方法用于比较两个对象的值是否相等,而hashCode()方法用于计算对象的哈希码。...
其中,equals和hashCode方法是Java容器集合中两个非常重要的方法,本文将详细介绍这两个方法,并结合ArrayList、Vector和LinkedList三个常见的容器集合。 一、equals方法 equals方法是Java中用于比较两个对象是否...
Java 中的 hashCode 和 equals 方法详解 本文详细介绍了 Java 中的 hashCode 和 equals 方法,探讨了这两个方法的作用、实现机制和使用场景。通过对 hashCode 和 equals 方法的深入分析,我们可以更好地理解 Java ...
equals 方法和 hashCode 方法是 Java 语言中两个重要的方法,它们都是在 Object 类中定义的。equals 方法用于比较两个对象是否相等,而 hashCode 方法用于返回对象的哈希码。 在 Java 的 Object 类中,equals 方法...
Java 中的每个对象都有 hashCode() 和 equals() 方法,这两个方法的正确实现对于 Java 开发人员来说是非常重要的。本文将详细介绍 hashCode() 和 equals() 的本质区别和联系,并探讨在创建 Java 类时如何定义这些...
为了使对象能够被正确地存储在基于散列的集合(如`HashSet`、`HashMap`)中,`equals`方法和`hashCode`方法必须保持一致。这意味着如果两个对象根据`equals`方法被认为是相等的,那么它们的`hashCode`方法也必须返回...
在这个例子中,`equals`方法根据`name`和`age`属性来判断两个`Person`对象是否相等,而`hashCode`方法也综合考虑了这两个属性,以确保`equals`方法返回`true`的对象具有相同的哈希码。 #### 七、总结 在Java中,...
在Java编程语言中,`hashCode()`和`equals()`方法是对象身份验证的关键组成部分,它们主要用于对象的比较和哈希表(如HashMap、HashSet等)的操作。理解这两个方法的工作原理对于编写高效和可靠的代码至关重要。 ...