Object类分析(equals和hashCode知识点)

所有的java对象都隐式继承了Object类对象。所有的java对象都拥有Object默认的方法。

public final native Class<?>getClass();//返回字节码文件对象 java反射实现方式之一
 public native int hashCode();
public boolean equals(Object obj)
protected Object clone();
public String toString();
public final void notify();
public final void notifyAll();
public final void wait(long timeout);
protected void finalized();

1.equals和hashCode

查看完文档以后我们查看源码,发现hashCode是由native关键字修饰,equals方法则是直接使用==比较了内存地址。

public boolean equals(Object obj) {
        return (this == obj);
    }

equals和hashCode用来标识对象,可以在非排序的情况下比较两个对象是否相等(对象数组中可以使用比较器)。

那么我们仔细关注一下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.)
  1. 返回一个哈希值给对象,这个方法有益于底层结构是哈希表的结构对象,例如HashMap
  2. 如果两个对象的equals的结果是相等的,则调用hashCode返回的int也必须是相同的
  3. 如果两个对象的equals不相等,hashCode可以不相等,但是如果equasl不相等,hashCode也不相等的话,有利于提高散列性能。(Map集合和Set集合底层判断重复的时候,先判断hashCode是否相等,如相等,再判断key的equals是否相等,一旦短路与&&生效,会大大提高程序执行效率。)
  4. hashCode默认是由对象的地址转换而来,同时根据不同的对象转成不同的hash值(但这种实现不是java语言要求的 所以我们常常重写它)

适用场景:我们在适用自定义对象作为Map/Set键时,为了区分不同对象,必须重写hashCode和equals。

延申:equals和==的区别:
对于基本类型而言,==比较的是内容。
对于引用数据类型而言,==比较的是地址。
对于引用数据类型(String,Integer,date等),重写了equals和hashCode的,比较的就是内容。
对于引用数据类型,没有重写equals和hashCode的,适用的还是Object的equals方法,比较的是地址。

再延申:那我们就去看一看String重写的equals源码吧:

 public boolean equals(Object anObject) {
        if (this == anObject) {//先判断地址是否相等,地址相等直接返回
            return true;
        }
        if (anObject instanceof String) {//判断是否是String类,为了向下转型的安全
            String anotherString = (String)anObject;
            int n = value.length;//value就是本String转化成的字符数组
            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;
    }

OK,那么我们知道了,String先是判断两个对象的地址是否相等,然后向下转型,再转成字符数组,从后向前遍历比较。

2.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());
    }
  1. 用文本方式标识一个对象
  2. Object默认返回的是 字节码文件的名称+@+一个内存地址的int映射

clone()方法

一般java的赋值是复制对象的引用(=),(类初始化状态不一)浅拷贝。要实现深拷贝,(连成员变量初始化状态都一样)成员变量都拷贝出去一份(如果是可变的引用),因而"="是属于浅拷贝。
所以深拷贝是成员变量(如果是可变的引用)都复制一份,浅拷贝则是不复制成员变量。两者初始化程度不一。

clone用法:

  1. 克隆的对象要实现Cloneable接口
  2. 重写clone方法,最好修饰成public

范例:浅拷贝Time

public class Time implements Cloneable{

    //可变成员变量
    private Date date;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

范例:深拷贝Time

public class Time implements Cloneable{

    //可变成员变量
    private Date date;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //向下转型 拷贝Time对象
        Time time=(Time)super.clone();

        //拷贝可变的成员变量
        time.date=(Date)date.clone();

        //返回拷贝的对象
        return time;
    }
}

wait和notify方法

这是线程间通信的API

  1. 无论是wait、notify还是notifyAll()都需要由监听器对象(锁对象)来进行调用,他们都是在同步代码块中调用的,否则会抛出异常!
  2. notify()唤醒的是在等待队列的某个线程(不确定会唤醒哪个),notifyAll()唤醒的是等待队列所有线程
  3. 导致wait()的线程被唤醒可以有4种情况
  • 该线程被中断
  • wait()时间到了
  • 被notify()唤醒
  • 被notifyAll()唤醒
  1. 调用wait()的线程会释放掉锁

一些面试题:
为什么wait和notify在Object方法上?
因为锁是对象锁,让线程等待某个对象的锁,应该由对象来操作

notify方法调用后,会发生什么?
会唤醒等待队列的某个线程
注:并不会立刻唤醒,会等notify的synchronized代码块执行完之后才会获得锁对象

Thread.sleep和Object.wait区别?
sleep不会释放对象锁的控制,而wait会。

finalize方法

这是在GC前会被JVM调用的方法,用来对一些特定的内存进行GC,一般不重写,对一些JNI操作的gc会使用。

因而hashCode和equals用于对象比较,clone用于对象克隆,toString用于对象标识,notify与wait是对象锁相关。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345

推荐阅读更多精彩内容