Java Object 类方法解析

本文详细解析了Java中Object类的几个关键方法,包括getClass()、hashCode()、equals()、clone()、toString()、wait/notify/notifyAll()和finalize()。通过源码分析和实例演示,阐述了这些方法的用途、工作原理及其在实际开发中的应用,特别是与Java容器、多线程和垃圾回收的关联。了解这些方法有助于提升Java开发的效率和质量。
摘要由CSDN通过智能技术生成

本文标题大纲:

前言

我们都知道 Java 语言是面向对象的编程语言,而面向对象编程以类作为基本单元。我们也都知道,在 Java 中,所有的类都将 Object 类作为父类,而 Object 类本身提供了一些基础但是很有用的方法,这些方法我们在日常工作中经常会用到,因此熟悉它们的原理和用法对我们的开发会有很大的帮助,下面我们来一起看一些这些方法:

getClass

这个方法用来动态的获取当前对象的类型信息,我们看看这个方法的源码声明:

/**
 * Returns the runtime class of this {@code Object}. The returned
 * {@code Class} object is the object that is locked by {@code
 * static synchronized} methods of the represented class.
 *
 * <p><b>The actual result type is {@code Class<? extends |X|>}
 * where {@code |X|} is the erasure of the static type of the
 * expression on which {@code getClass} is called.</b> For
 * example, no cast is required in this code fragment:</p>
 *
 * <p>
 * {@code Number n = 0;                             }<br>
 * {@code Class<? extends Number> c = n.getClass(); }
 * </p>
 *
 * @return The {@code Class} object that represents the runtime
 *         class of this object.
 * @jls 15.8.2 Class Literals
 */
public final native Class<?> getClass();

这是一个 final 类型的 native 方法,也就是说这个方法不能被子类重写,同时它的实现并不是通过 Java 语言实现的,而是用其他语言(C/C++)实现的,我们得到某个对象的类型信息(Class 类的对象)之后,我们就可以利用 Java 反射的机制做很多事情了,比如有以下代码:

public class Main {
   

    static class People {
   
        String name;

        public People(String name) {
   
            this.name = name;
        }

        public void work() {
   
            System.out.println(name + " is working!");
        }
    }

    private static void startTest() {
   
        People p1 = new People("指点");
        p1.work();
        // 获取 p1 对象的类型信息,在这里编译器只知道 p1 是 People 类型的对象的引用,
        // 但是编译器并不知道具体是 People 类型的对象还是 People 的子类对象(虽然在这里并没有 People 的子类),
        // 所以我们这里用泛型必须加类型边界限定符,
        // 当然也可以不加,这样就代表这是一个任意类型的 Class 对象
        Class<? extends People> cp = p1.getClass();
        People p2 = null;
        try {
   
            // 获取 cp 代表的 Class 对象的具有一个 String 类型的构造方法,
            // 再使用这个构造方法新建一个对象并将 p2 引用指向这个对象,
            // 即为通过反射的方式创建对象
            p2 = cp.getConstructor(String.class).newInstance("另一个人");
        } catch (Exception e) {
   
            e.printStackTrace();
        }
        if (p2 != null) {
   
            p2.work();
        }
    }

    public static void main(String[] args) {
   
        startTest();
    }
}

在这里我们获取了 p1 的类型信息之后利用反射新建了一个 People 对象,并调用了它的 work() 方法,我们来看看结果:
这里写图片描述
Ok,其实得到了一个对象的 Class 类型对象之后我们能做的事情有很多(新建对象,调用方法,甚至访问类私有属性/方法…)。当然这些都是 Java 反射的内容,有兴趣的小伙伴可以查找相关资料。

hashCode

这个方法算是相对比较常见的一个方法了,我们看看它的源码声明:

/**
 * 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&trade; 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();

同样的,这个方法默认是利用 C/C++ 语言实现的,这个方法可以返回一个对象的哈希值,这个值在一定程度上可以标志一个对象。默认情况下,这个值会和当前对象所在内存中的地址有一定的关系(这取决于 JVM 的实现),当然,我们在子类中可以根据子类的特性选择重写这个方法。而提到 hashCode 方法就不得不提 Java 中的 Map 接口下的相关容器了,因为 Map 接口下的一些容器(HashMapIdentityHashMap)正是通过对象的 hashCode 方法进行工作的,在 HashMap 中,会有一个名为 table 的数组字段,这个数组字段用来储存 HashMap 中每一个键值对关系,即为映射表,每当储存一个新的键值对进入当前的 HashMap 对象的时候,都会调用这个键值对中的 “键” 对象的 hashCode 方法并将其返回的哈希值进行一定的处理,然后将这个结果作为数组的下标并且将要储存的键值对储存在 table 数组的这个下标元素中。当然这种做法可能会产生冲突,即多个键值对储存时得到的下标值相同,关于 HashMap 处理冲突细节,可以参考一下我的下一篇文章。
除此之外,我们还在利用 hashCode 方法时需要注意一些问题:

1、如果两个对象的 hashCode 返回值相同,我们不能直接说它们相等,原因很简单:这个方法本身可以被子类重写,我只需要定义一个类 A 并且重写这个方法然后让它返回一个固定值就行了,这样的话所有 A 类的对象的 hashCode 方法返回值都相同,但实际上它们并不是同一个对象。
2、但是反过来:如果两个对象的 hashCode 值不相等,那么我们就可以判断这两个对象一定不同(不是同一个对象)。这个道理很容易明白:如果两个引用指向同一个对象,那么这两个引用调用的 hashCode 方法一定是同一个对象的 hashCode 方法,同一个对象在同一时刻的 hashCode 方法返回值肯定相同,那么如果两个对象的 hashCode 值不同,那么我们也可以判断这两个对象不等(内存上不是同一个对象)。

那么在我们自定义的类中我们如何去重写这个方法呢,在《Java 编程思想》中提供了一个关于如何在自定义类中编写一个合理的 hashCode 方法的参考:
这里写图片描述
JDK 里面已经提供了工具方法来帮助我们计算一个复杂类对象的 hashCode 值,我们来看看这个方法(java.util.Objects#hash):

/**
    * Generates a hash code for a sequence of input values. The hash
    * code is generated as if all the input values were placed into an
    * array, and that array were hashed by calling {@link
    * Arrays#hashCode(Object[])}.
    *
    * <p>This method is useful for implementing {@link
    * Object#hashCode()} on objects containing multiple fields. For
    * example, if an object that has three fields, {@code x}, {@code
    * y}, and {@code z}, one could write:
    *
    * <blockquote><pre>
    * &#064;Override public int hashCode() {
    *     return Objects.hash(x, y, z);
    * }
    * </pre></blockquote>
    *
    * <b>Warning: When a single object reference is supplied, the returned
    * value does not equal the hash code of that object reference.</b> This
    * value can be computed by calling {@link #hashCode(Object)}.
    *
    * @param values the values to be hashed
    * @return a hash value of the sequence of input values
    * @see Arrays#hashCode(Object[])
    * @see List#hashCode
    */
    public static int hash(Object... values) {
   
        return Arrays.hashCode(values);
    }

调用了 Arrays.hashCode 方法,我们继续跟进 java.util.Arrays#hashCode(java.lang.Object[])

/**
     * Returns a hash code based on the contents of the specified array.  If
     * the array contains other arrays as elements, the hash code is based on
     * their identities rather than their contents.  It is therefore
     * acceptable to invoke this method on an array that contains itself as an
     * element,  either directly or indirectly through one or more levels of
     * arrays.
     *
     * <p>For any two arrays <tt>a</tt> and <tt>b</tt> such that
     * <tt>Arrays.equals(a, b)</tt>, it is also the case that
     * <tt>Arrays.hashCode(a) == Arrays.hashCode(b)</tt>.
     *
     * <p>The value returned by this method is equal to the value that would
     * be returned by <tt>Arrays.asList(a).hashCode()</tt>, unless <tt>a</tt>
     * is <tt>null</tt>, in which case <tt>0</tt> is returned.
     *
     * @param a the array whose content-based hash code to compute
     * @return a content-based hash code for <tt>a</tt>
     * @see #deepHashCode(Object[])
     * @since 1.5
     */
    public static int hashCode(Object a[]) {
   
        if (a == null)
            return 0
  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值