Java 是一门纯面向对象的编程语言,Java 世界里万物皆对象,这些对象的祖宗就是 Object 类了。学习其他类实现的过程中,难免与 Object 打交道,所以这里记录下学习过程中的笔记吧!
First Blood
首先是在学习 HashMap、HashTable 的过程中遇到了关于 Object 类的 hashCode 和 equals 这两方法的讨论,那就去看看 JDK 源码里是怎么描述这两个方法的吧:
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link java.lang.Object#equals(java.lang.Object)}
* method, then calling the {@code hashCode} method on each of the
* two objects must produce distinct integer results. However, the
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
* </ul>
* <p>
* As much as is reasonably practical, the hashCode method defined by
* class {@code Object} does return distinct integers for distinct
* objects. (This is typically implemented by converting the internal
* address of the object into an integer, but this implementation
* technique is not required by the
* Java™ programming language.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
public native int hashCode();
注释里先说了 hashCode 方法就是服务于哈希表数据结构类(比如 HashMap),该方法是 JDK 原生方法,具体实现可能随着 JDK 厂商版本不同而不同,所以我们就不去看其具体实现了,就只说说其一般约定吧:
- 在同一次运行中的 JVM 里,同一个对象的 hashCode 方法返回值应当一致;不时同一次运行的时,该方法返回值可以不一致;
- 如果两个对象通过 equals 方法判等时结果返回真,那么这两个对象调用 hashCode 方法的返回值应该一致;
- 两个不同对象调用 hashCode 方法并不强制其返回结果必须不一致,但是其返回结果不一致时哈希表的性能更高;
- JDK 实现里,鉴于实用原则,不同对象的 hashCode 方法返回值确实是不一致的(实现原理大致就是将该对象的内存地址做一些处理后返回),但是这一点在《Java 编程规范》中并未做强制要求;
然后再说 equals 方法:
/**
* Indicates whether some other object is "equal to" this one.
* <p>
* The {@code equals} method implements an equivalence relation
* on non-null object references:
* <ul>
* <li>It is <i>reflexive</i>: for any non-null reference value
* {@code x}, {@code x.equals(x)} should return
* {@code true}.
* <li>It is <i>symmetric</i>: for any non-null reference values
* {@code x} and {@code y}, {@code x.equals(y)}
* should return {@code true} if and only if
* {@code y.equals(x)} returns {@code true}.
* <li>It is <i>transitive</i>: for any non-null reference values
* {@code x}, {@code y}, and {@code z}, if
* {@code x.equals(y)} returns {@code true} and
* {@code y.equals(z)} returns {@code true}, then
* {@code x.equals(z)} should return {@code true}.
* <li>It is <i>consistent</i>: for any non-null reference values
* {@code x} and {@code y}, multiple invocations of
* {@code x.equals(y)} consistently return {@code true}
* or consistently return {@code false}, provided no
* information used in {@code equals} comparisons on the
* objects is modified.
* <li>For any non-null reference value {@code x},
* {@code x.equals(null)} should return {@code false}.
* </ul>
* <p>
* The {@code equals} method for class {@code Object} implements
* the most discriminating possible equivalence relation on objects;
* that is, for any non-null reference values {@code x} and
* {@code y}, this method returns {@code true} if and only
* if {@code x} and {@code y} refer to the same object
* ({@code x == y} has the value {@code true}).
* <p>
* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
*
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @see #hashCode()
* @see java.util.HashMap
*/
public boolean equals(Object obj) {
return (this == obj);
}
可以看到该方法的实现是用双等号做判等校验的,这样其实就是比较两个对象的内存地址。该方法有一些特性:
- 自反省
- 对象性
- 传递性
- 一致性
熟悉的感觉,好像那个高中数学公理也有这样的特性。
该方法的参数可以是 null,由此看见:在 Java 中 null 虽非对象,却是可以作为对象实例的值;
还有一点要注意:覆写 equals 方法后要记得覆写 hashCode 方法,以维持 hashCode 方法的第二个约定:如果两个对象通过 equals 方法判等时结果返回真,那么这两个对象调用 hashCode 方法的返回值应该一致;
Double Kill
熟悉了上面的 hashCode 方法和 equals 方法的作用,那么再看 toString 方法就易如反掌了:
/**
* Returns a string representation of the object. In general, the
* {@code toString} method returns a string that
* "textually represents" this object. The result should
* be a concise but informative representation that is easy for a
* person to read.
* It is recommended that all subclasses override this method.
* <p>
* The {@code toString} method for class {@code Object}
* returns a string consisting of the name of the class of which the
* object is an instance, the at-sign character `{@code @}', and
* the unsigned hexadecimal representation of the hash code of the
* object. In other words, this method returns a string equal to the
* value of:
* <blockquote>
* <pre>
* getClass().getName() + '@' + Integer.toHexString(hashCode())
* </pre></blockquote>
*
* @return a string representation of the object.
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
为了人类的可读性,toString 方法把 hashCode 方法返回的整数类型转换为了十六进制字符串类型。