一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Object類中的所有方法

科技綠洲 ? 來源:Java技術(shù)指北 ? 作者:Java技術(shù)指北 ? 2023-10-13 11:50 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Object 類屬于 java.lang 包,此包下的所有類在使用時(shí)無需手動導(dǎo)入,系統(tǒng)會在程序編譯期間自動導(dǎo)入。Object 類是所有類的基類,當(dāng)一個(gè)類沒有直接繼承某個(gè)類時(shí),默認(rèn)繼承Object類,也就是說任何類都直接或間接繼承此類,Object 類中能訪問的方法在所有類中都可以調(diào)用,下面我們會分別介紹Object 類中的所有方法。

1、Object 類的結(jié)構(gòu)圖

圖片

Object.class類

/*
 * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */

package java.lang;

/**
 * Class {@code Object} is the root of the class hierarchy.
 * Every class has {@code Object} as a superclass. All objects,
 * including arrays, implement the methods of this class.
 *
 * @author  unascribed
 * @see     java.lang.Class
 * @since   JDK1.0
 */
public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }

    public final native Class< ? > getClass();

    public native int hashCode();

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

    protected native Object clone() throws CloneNotSupportedException;
    
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

    public final native void notify();
    
    public final native void notifyAll();
    
    public final native void wait(long timeout) throws InterruptedException;
    
    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                    "nanosecond timeout value out of range");
        }
        if (nanos > 0) {
            timeout++;
        }
        wait(timeout);
    }
    
    public final void wait() throws InterruptedException {
        wait(0);
    }
    
    protected void finalize() throws Throwable { }
}

2、 為什么java.lang包下的類不需要手動導(dǎo)入?

不知道大家注意到?jīng)],我們在使用諸如Date類時(shí),需要手動導(dǎo)入import java.util.Date,再比如使用File類時(shí),也需要手動導(dǎo)入import java.io.File。但是我們在使用Object類,String 類,Integer類等不需要手動導(dǎo)入,而能直接使用,這是為什么呢?

這里先告訴大家一個(gè)結(jié)論:使用 java.lang 包下的所有類,都不需要手動導(dǎo)入。

另外我們介紹一下Java中的兩種導(dǎo)包形式,導(dǎo)包有兩種方法:

①、單類型導(dǎo)入(single-type-import),例如import java.util.Date

②、按需類型導(dǎo)入(type-import-on-demand),例如import java.util.*

單類型導(dǎo)入比較好理解,我們編程所使用的各種工具默認(rèn)都是按照單類型導(dǎo)包的,需要什么類便導(dǎo)入什么類,這種方式是導(dǎo)入指定的public類或者接口;

按需類型導(dǎo)入,比如 import java.util.*,可能看到后面的 *,大家會以為是導(dǎo)入java.util包下的所有類,其實(shí)并不是這樣,我們根據(jù)名字按需導(dǎo)入要知道他是按照需求導(dǎo)入,并不是導(dǎo)入整個(gè)包下的所有類。

Java編譯器會從啟動目錄(bootstrap),擴(kuò)展目錄(extension)和用戶類路徑下去定位需要導(dǎo)入的類,而這些目錄僅僅是給出了類的頂層目錄,編譯器的類文件定位方法大致可以理解為如下公式:

頂層路徑名 包名 文件名.class = 絕對路徑

單類型導(dǎo)入我們知道包名和文件名,所以編譯器可以一次性查找定位到所要的類文件。按需類型導(dǎo)入則比較復(fù)雜,編譯器會把包名和文件名進(jìn)行排列組合,然后對所有的可能性進(jìn)行類文件查找定位。例如:

package com;

import java.io.*;

import java.util.*;

如果我們文件中使用到了 File 類,那么編譯器會根據(jù)如下幾個(gè)步驟來進(jìn)行查找 File 類:

①、File // File類屬于無名包,就是說File類沒有package語句,編譯器會首先搜索無名包

②、com.File // File類屬于當(dāng)前包,就是我們當(dāng)前編譯類的包路徑

③、java.lang.File //由于編譯器會自動導(dǎo)入java.lang包,所以也會從該包下查找

④、java.io.File

⑤、java.util.File

......

需要注意的地方就是,編譯器找到j(luò)ava.io.File類之后并不會停止下一步的尋找,而要把所有的可能性都查找完以確定是否有類導(dǎo)入沖突。假設(shè)此時(shí)的頂層路徑有三個(gè),那么編譯器就會進(jìn)行3*5=15次查找。

如果在查找完成后,編譯器發(fā)現(xiàn)了兩個(gè)同名的類,那么就會報(bào)錯(cuò)。要?jiǎng)h除你不用的那個(gè)類,然后再編譯。

所以我們可以得出這樣的結(jié)論:按需類型導(dǎo)入是絕對不會降低Java代碼的執(zhí)行效率的,但會影響到Java代碼的編譯速度。所以我們在編碼時(shí)最好是使用單類型導(dǎo)入,這樣不僅能提高編譯速度,也能避免命名沖突。

講清楚Java的兩種導(dǎo)包類型了,我們再回到為什么可以直接使用 Object 類,看到上面查找類文件的第③步,編譯器會自動導(dǎo)入 java.lang 包,那么當(dāng)然我們能直接使用了。至于原因,因?yàn)橛玫亩?,提前加載了,省資源。

3、類構(gòu)造器

我們知道類構(gòu)造器是創(chuàng)建Java對象的途徑之一,通過new 關(guān)鍵字調(diào)用構(gòu)造器完成對象的實(shí)例化,還能通過構(gòu)造器對對象進(jìn)行相應(yīng)的初始化。一個(gè)類必須要有一個(gè)構(gòu)造器的存在,如果沒有顯示聲明,那么系統(tǒng)會默認(rèn)創(chuàng)造一個(gè)無參構(gòu)造器,在JDK的Object類源碼中,是看不到構(gòu)造器的,系統(tǒng)會自動添加一個(gè)無參構(gòu)造器。我們可以通過:

Object obj = new Object();構(gòu)造一個(gè)Object類的對象。

4、equals 方法

通常很多面試題都會問 equals() 方法和 == 運(yùn)算符的區(qū)別,== 運(yùn)算符用于比較基本類型的值是否相同,或者比較兩個(gè)對象的引用是否相等,而 equals 用于比較兩個(gè)對象是否相等,這樣說可能比較寬泛,兩個(gè)對象如何才是相等的呢?這個(gè)標(biāo)尺該如何定?我們可以看看 Object 類中的equals 方法:

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

可以看到,在 Object 類中,== 運(yùn)算符和 equals 方法是等價(jià)的,都是比較兩個(gè)對象的引用是否相等,從另一方面來講,如果兩個(gè)對象的引用相等,那么這兩個(gè)對象一定是相等的。對于我們自定義的一個(gè)對象,如果不重寫 equals 方法,那么在比較對象的時(shí)候就是調(diào)用 Object 類的 equals 方法,也就是用 == 運(yùn)算符比較兩個(gè)對象。我們可以看看 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;
    }

String 是引用類型,比較時(shí)不能比較引用是否相等,重點(diǎn)是字符串的內(nèi)容是否相等。所以 String 類定義兩個(gè)對象相等的標(biāo)準(zhǔn)是字符串內(nèi)容都相同。

在Java規(guī)范中,對 equals 方法的使用必須遵循以下幾個(gè)原則:

①、自反性:對于任何非空引用值 x,x.equals(x) 都應(yīng)返回 true。

②、對稱性:對于任何非空引用值 x 和 y,當(dāng)且僅當(dāng) y.equals(x) 返回 true 時(shí),x.equals(y) 才應(yīng)返回 true。

③、傳遞性:對于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 應(yīng)返回 true。

④、一致性:對于任何非空引用值 x 和 y,多次調(diào)用 x.equals(y) 始終返回 true 或始終返回 false,前提是對象上 equals 比較中所用的信息沒有被修改

⑤、對于任何非空引用值 x,x.equals(null) 都應(yīng)返回 false。

下面我們自定義一個(gè) Person 類,然后重寫其equals 方法,比較兩個(gè) Person 對象:

package com.ys.bean;
/**
 * Create by vae
 */
public class Person {
    private String pname;
    private int page;

    public Person(){}

    public Person(String pname,int page){
        this.pname = pname;
        this.page = page;
    }
    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public String getPname() {
        return pname;
    }

    public void setPname(String pname) {
        this.pname = pname;
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj){//引用相等那么兩個(gè)對象當(dāng)然相等
            return true;
        }
        if(obj == null || !(obj instanceof  Person)){//對象為空或者不是Person類的實(shí)例
            return false;
        }
        Person otherPerson = (Person)obj;
        if(otherPerson.getPname().equals(this.getPname()) && otherPerson.getPage()==this.getPage()){
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Person p1 = new Person("Tom",21);
        Person p2 = new Person("Marry",20);
        System.out.println(p1==p2);//false
        System.out.println(p1.equals(p2));//false

        Person p3 = new Person("Tom",21);
        System.out.println(p1.equals(p3));//true
    }

}

通過重寫 equals 方法,我們自定義兩個(gè)對象相等的標(biāo)尺為Person對象的兩個(gè)屬性都相等,則對象相等,否則不相等。如果不重寫 equals 方法,那么始終是調(diào)用 Object 類的equals 方法,也就是用 == 比較兩個(gè)對象在棧內(nèi)存中的引用地址是否相等。

這時(shí)候有個(gè)Person 類的子類 Man,也重寫了 equals 方法:

package com.ys.bean;
/**
 * Create by vae
 */
public class Man extends Person{
    private String sex;

    public Man(String pname,int page,String sex){
        super(pname,page);
        this.sex = sex;
    }
    @Override
    public boolean equals(Object obj) {
        if(!super.equals(obj)){
            return false;
        }
        if(obj == null || !(obj instanceof  Man)){//對象為空或者不是Person類的實(shí)例
            return false;
        }
        Man man = (Man) obj;
        return sex.equals(man.sex);
    }

    public static void main(String[] args) {
        Person p = new Person("Tom",22);
        Man m = new Man("Tom",22,"男");

        System.out.println(p.equals(m));//true
        System.out.println(m.equals(p));//false
    }
}

通過打印結(jié)果我們發(fā)現(xiàn) person.equals(man)得到的結(jié)果是 true,而man.equals(person)得到的結(jié)果卻是false,這顯然是不正確的。

問題出現(xiàn)在 instanceof 關(guān)鍵字上,關(guān)于 instanceof 關(guān)鍵字的用法,可以參考我的這篇文章:http://www.cnblogs.com/ysocean/p/8486500.html

Man 是 Person 的子類,person instanceof Man 結(jié)果當(dāng)然是false。這違反了我們上面說的對稱性。

實(shí)際上用 instanceof 關(guān)鍵字是做不到對稱性的要求的。這里推薦做法是用 getClass()方法取代 instanceof 運(yùn)算符。getClass() 關(guān)鍵字也是 Object 類中的一個(gè)方法,作用是返回一個(gè)對象的運(yùn)行時(shí)類,下面我們會詳細(xì)講解。

那么 Person 類中的 equals 方法為

public boolean equals(Object obj) {
        if(this == obj){//引用相等那么兩個(gè)對象當(dāng)然相等
            return true;
        }
        if(obj == null || (getClass() != obj.getClass())){//對象為空或者不是Person類的實(shí)例
            return false;
        }
        Person otherPerson = (Person)obj;
        if(otherPerson.getPname().equals(this.getPname()) && otherPerson.getPage()==this.getPage()){
            return true;
        }
        return false;
    }

打印結(jié)果 person.equals(man)得到的結(jié)果是 false,man.equals(person)得到的結(jié)果也是false,滿足對稱性。

注意:使用 getClass 不是絕對的,要根據(jù)情況而定,畢竟定義對象是否相等的標(biāo)準(zhǔn)是由程序員自己定義的。而且使用 getClass 不符合多態(tài)的定義,比如 AbstractSet 抽象類,它有兩個(gè)子類 TreeSet 和 HashSet,他們分別使用不同的算法實(shí)現(xiàn)查找集合的操作,但無論集合采用哪種方式實(shí)現(xiàn),都需要擁有對兩個(gè)集合進(jìn)行比較的功能,如果使用 getClass 實(shí)現(xiàn)equals方法的重寫,那么就不能在兩個(gè)不同子類的對象進(jìn)行相等的比較。而且集合類比較特殊,其子類是不需要自定義相等的概念的。

所以什么時(shí)候使用 instanceof 運(yùn)算符,什么時(shí)候使用 getClass() 有如下建議:

①、如果子類能夠擁有自己的相等概念,則對稱性需求將強(qiáng)制采用 getClass 進(jìn)行檢測。

②、如果有超類決定相等的概念,那么就可以使用 instanceof 進(jìn)行檢測,這樣可以在不同的子類的對象之間進(jìn)行相等的比較。

下面給出一個(gè)完美的 equals 方法的建議:

1、顯示參數(shù)命名為 otherObject,稍后會將它轉(zhuǎn)換成另一個(gè)叫做 other 的變量。

2、判斷比較的兩個(gè)對象引用是否相等,如果引用相等那么表示是同一個(gè)對象,那么當(dāng)然相等

3、如果 otherObject 為 null,直接返回false,表示不相等

4、比較 this 和 otherObject 是否是同一個(gè)類:如果 equals 的語義在每個(gè)子類中有所改變,就使用 getClass 檢測;如果所有的子類都有統(tǒng)一的定義,那么使用 instanceof 檢測

5、將 otherObject 轉(zhuǎn)換成對應(yīng)類的類型變量

6、最后對對象的屬性進(jìn)行比較。使用 == 比較基本類型,使用 equals 比較對象。如果都相等則返回true,否則返回false。注意如果是在子類中定義equals,則要包含 super.equals(other)

下面我們給出 Person 類中完整的 equals 方法的書寫:

@Override
    public boolean equals(Object otherObject) {
        //1、判斷比較的兩個(gè)對象引用是否相等,如果引用相等那么表示是同一個(gè)對象,那么當(dāng)然相等
        if(this == otherObject){
            return true;
        }
        //2、如果 otherObject 為 null,直接返回false,表示不相等
        if(otherObject == null ){//對象為空或者不是Person類的實(shí)例
            return false;
        }
        //3、比較 this 和 otherObject 是否是同一個(gè)類(注意下面兩個(gè)只能使用一種)
        //3.1:如果 equals 的語義在每個(gè)子類中所有改變,就使用 getClass 檢測
        if(this.getClass() != otherObject.getClass()){
            return false;
        }
        //3.2:如果所有的子類都有統(tǒng)一的定義,那么使用 instanceof 檢測
        if(!(otherObject instanceof Person)){
            return false;
        }

        //4、將 otherObject 轉(zhuǎn)換成對應(yīng)的類類型變量
        Person other = (Person) otherObject;

        //5、最后對對象的屬性進(jìn)行比較。使用 == 比較基本類型,使用 equals 比較對象。如果都相等則返回true,否則返回false
        //   使用 Objects 工具類的 equals 方法防止比較的兩個(gè)對象有一個(gè)為 null而報(bào)錯(cuò),因?yàn)?null.equals() 是會拋異常的
        return Objects.equals(this.pname,other.pname) && this.page == other.page;

        //6、注意如果是在子類中定義equals,則要包含 super.equals(other)
        //return super.equals(other) && Objects.equals(this.pname,other.pname) && this.page == other.page;

    }

請注意,無論何時(shí)重寫此方法,通常都必須重寫hashCode方法,以維護(hù)hashCode方法的一般約定,該方法聲明相等對象必須具有相同的哈希代碼。hashCode 也是 Object 類中的方法,后面會詳細(xì)講解 。

5、getClass 方法

上面我們在介紹 equals 方法時(shí),介紹如果 equals 的語義在每個(gè)子類中有所改變,那么使用 getClass 檢測,為什么這樣說呢?

getClass()在 Object 類中如下,作用是返回對象的運(yùn)行時(shí)類。

public final native Class< ? > getClass();

這是一個(gè)用 native 關(guān)鍵字修飾的方法,關(guān)于 native 關(guān)鍵字的詳細(xì)介紹如下:http://www.cnblogs.com/ysocean/p/8476933.html

這里我們要知道用 native 修飾的方法我們不用考慮,由操作系統(tǒng)幫我們實(shí)現(xiàn),該方法的作用是返回一個(gè)對象的運(yùn)行時(shí)類,通過這個(gè)類對象我們可以獲取該運(yùn)行時(shí)類的相關(guān)屬性和方法。也就是Java中的反射,各種通用的框架都是利用反射來實(shí)現(xiàn)的,這里我們不做詳細(xì)的描述。

這里詳細(xì)的介紹 getClass 方法返回的是一個(gè)對象的運(yùn)行時(shí)類對象,這該怎么理解呢?Java中還有一種這樣的用法,通過 類名.class 獲取這個(gè)類的類對象 ,這兩種用法有什么區(qū)別呢?

父類:Parent.class

public class Parent {}

子類:Son.class

public class Son extends Parent{}

測試:

@Test
public void testClass(){
    Parent p = new Son();
    System.out.println(p.getClass());
    System.out.println(Parent.class);
}

打印結(jié)果:

圖片結(jié)論:class 是一個(gè)類的屬性,能獲取該類編譯時(shí)的類對象,而 getClass() 是一個(gè)類的方法,它是獲取該類運(yùn)行時(shí)的類對象。

還有一個(gè)需要大家注意的是,雖然Object類中g(shù)etClass() 方法聲明是:public final native Class getClass();返回的是一個(gè) Class,但是如下是能通過編譯的:

Class< ? extends String > c = "".getClass();

也就是說類型為T的變量getClass方法的返回值類型其實(shí)是Class而非getClass方法聲明中的Class。

這在官方文檔中也有說明:https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#getClass--

6、hashCode 方法

hashCode 在 Object 類中定義如下:

public native int hashCode();

這也是一個(gè)用 native 聲明的本地方法,作用是返回對象的散列碼,是 int 類型的數(shù)值。

那么這個(gè)方法存在的意義是什么呢?

我們知道在Java 中有幾種集合類,比如 List、Set,還有 Map,List集合一般是存放的元素是有序可重復(fù)的,Set 存放的元素則是無序不可重復(fù)的,而 Map 集合存放的是鍵值對。

前面我們說過判斷一個(gè)元素是否相等可以通過 equals 方法,每增加一個(gè)元素,那么我們就通過 equals 方法判斷集合中的每一個(gè)元素是否重復(fù),但是如果集合中有10000個(gè)元素了,但我們新加入一個(gè)元素時(shí),那就需要進(jìn)行10000次equals方法的調(diào)用,這顯然效率很低。

于是,Java 的集合設(shè)計(jì)者就采用了 哈希表 來實(shí)現(xiàn)。關(guān)于哈希表的數(shù)據(jù)結(jié)構(gòu)我有過介紹。哈希算法也稱為散列算法,是將數(shù)據(jù)依特定算法產(chǎn)生的結(jié)果直接指定到一個(gè)地址上。這個(gè)結(jié)果就是由 hashCode 方法產(chǎn)生。這樣一來,當(dāng)集合要添加新的元素時(shí),先調(diào)用這個(gè)元素的 hashCode 方法,就一下子能定位到它應(yīng)該放置的物理位置上。

①、如果這個(gè)位置上沒有元素,它就可以直接存儲在這個(gè)位置上,不用再進(jìn)行任何比較了;

②、如果這個(gè)位置上已經(jīng)有元素了,就調(diào)用它的equals方法與新元素進(jìn)行比較,相同的話就不存了;

③、不相同的話,也就是發(fā)生了Hash key相同導(dǎo)致沖突的情況,那么就在這個(gè)Hash key的地方產(chǎn)生一個(gè)鏈表,將所有產(chǎn)生相同HashCode的對象放到這個(gè)單鏈表上去,串在一起(很少出現(xiàn))。這樣一來實(shí)際調(diào)用equals方法的次數(shù)就大大降低了,幾乎只需要一兩次。 圖片這里有 A,B,C,D四個(gè)對象,分別通過 hashCode 方法產(chǎn)生了三個(gè)值,注意 A 和 B 對象調(diào)用 hashCode 產(chǎn)生的值是相同的,即 A.hashCode() = B.hashCode() = 0x001,發(fā)生了哈希沖突,這時(shí)候由于最先是插入了 A,在插入的B的時(shí)候,我們發(fā)現(xiàn) B 是要插入到 A 所在的位置,而 A 已經(jīng)插入了,這時(shí)候就通過調(diào)用 equals 方法判斷 A 和 B 是否相同,如果相同就不插入 B,如果不同則將 B 插入到 A 后面的位置。所以對于 equals 方法和 hashCode 方法有如下要求:

一、hashCode 要求

①、在程序運(yùn)行時(shí)期間,只要對象的(字段的)變化不會影響equals方法的決策結(jié)果,那么,在這個(gè)期間,無論調(diào)用多少次hashCode,都必須返回同一個(gè)散列碼。

②、通過equals調(diào)用返回true 的2個(gè)對象的hashCode一定一樣。

③、通過equasl返回false 的2個(gè)對象的散列碼不需要不同,也就是他們的hashCode方法的返回值允許出現(xiàn)相同的情況。

因此我們可以得到如下推論:

兩個(gè)對象相等,其 hashCode 一定相同;

兩個(gè)對象不相等,其 hashCode 有可能相同;

hashCode 相同的兩個(gè)對象,不一定相等;

hashCode 不相同的兩個(gè)對象,一定不相等;

這四個(gè)推論通過上圖可以更好的理解。

可能會有人疑問,對于不能重復(fù)的集合,為什么不直接通過 hashCode 對于每個(gè)元素都產(chǎn)生唯一的值,如果重復(fù)就是相同的值,這樣不就不需要調(diào)用 equals 方法來判斷是否相同了嗎? 實(shí)際上對于元素不是很多的情況下,直接通過 hashCode 產(chǎn)生唯一的索引值,通過這個(gè)索引值能直接找到元素,而且還能判斷是否相同。比如數(shù)據(jù)庫存儲的數(shù)據(jù),ID 是有序排列的,我們能通過 ID 直接找到某個(gè)元素,如果新插入的元素 ID 已經(jīng)有了,那就表示是重復(fù)數(shù)據(jù),這是很完美的辦法。但現(xiàn)實(shí)是存儲的元素很難有這樣的 ID 關(guān)鍵字,也就很難這種實(shí)現(xiàn) hashCode 的唯一算法,再者就算能實(shí)現(xiàn),但是產(chǎn)生的 hashCode 碼是非常大的,這會大的超過 Java 所能表示的范圍,很占內(nèi)存空間,所以也是不予考慮的。

二、hashCode 編寫指導(dǎo):

①、不同對象的hash碼應(yīng)該盡量不同,避免hash沖突,也就是算法獲得的元素要盡量均勻分布。

②、hash 值是一個(gè) int 類型,在Java中占用 4 個(gè)字節(jié),也就是 2的32 次方,要避免溢出。

在 JDK 的 Integer類,F(xiàn)loat 類,String 類等都重寫了 hashCode 方法,我們自定義對象也可以參考這些類來寫。

下面是 JDK String 類的hashCode 源碼:

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;
    }

再次提醒大家,對于 Map 集合,我們可以選取Java中的基本類型,還有引用類型 String 作為 key,因?yàn)樗鼈兌及凑找?guī)范重寫了 equals 方法和 hashCode 方法。但是如果你用自定義對象作為 key,那么一定要覆寫 equals 方法和 hashCode 方法,不然會有意想不到的錯(cuò)誤產(chǎn)生。

7、toString 方法

該方法在 JDK 的源碼如下:

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

getClass().getName()是返回對象的全類名(包含包名),Integer.toHexString(hashCode()) 是以16進(jìn)制無符號整數(shù)形式返回此哈希碼的字符串表示形式。

打印某個(gè)對象時(shí),默認(rèn)是調(diào)用 toString 方法,比如 System.out.println(person),等價(jià)于 System.out.println(person.toString())

8、notify()/notifyAll()/wait()

這是用于多線程之間的通信方法,在后面講解多線程會詳細(xì)描述,這里就不做講解了。

protected void finalize() throws Throwable { }

該方法用于垃圾回收,一般由 JVM 自動調(diào)用,一般不需要程序員去手動調(diào)用該方法。后面再講解 JVM 的時(shí)候會詳細(xì)展開描述。

10、registerNatives 方法

該方法在 Object 類中定義如下:

private static native void registerNatives();

這是一個(gè)本地方法,在 native 介紹 中我們知道一個(gè)類定義了本地方法后,想要調(diào)用操作系統(tǒng)的實(shí)現(xiàn),必須還要裝載本地庫,但是我們發(fā)現(xiàn)在 Object.class 類中具有很多本地方法,但是卻沒有看到本地庫的載入代碼。而且這是用 private 關(guān)鍵字聲明的,在類外面根本調(diào)用不了,我們接著往下看關(guān)于這個(gè)方法的類似源碼:

static {
        registerNatives();
    }

看到上面的代碼,這就明白了吧。靜態(tài)代碼塊就是一個(gè)類在初始化過程中必定會執(zhí)行的內(nèi)容,所以在類加載的時(shí)候是會執(zhí)行該方法的,通過該方法來注冊本地方法。

11、小結(jié)

好了,這就是JDK中java.lang.Object類的源碼解析。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    2989

    瀏覽量

    109647
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1662

    瀏覽量

    50218
  • 程序編譯
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    5545
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    LABVIEW如何取得ActiveXOBJECT數(shù)據(jù)

    string bstrErrorMessage )這C#這個(gè)控件我VB VC DELPHI EXECLE 中試了都可以,就LABVIEW不行。LABVIEW如何取得ActiveXOB
    發(fā)表于 01-20 16:25

    6747串口有方法可以一次接收完所有字節(jié)后觸發(fā)cpu中斷嗎

    我想通過6747的UART定時(shí)的接收約50字節(jié)的數(shù)據(jù)進(jìn)行處理,6747UART的FIFO只有16字節(jié),這是說我只能在16字節(jié)以內(nèi)設(shè)置門限觸發(fā)中斷,有沒有方法可以一次接收完所有字節(jié)后觸發(fā)cpu中斷,謝謝!
    發(fā)表于 04-23 07:27

    如何使用Python的? 優(yōu)勢有哪些?

    個(gè)繼承了另外一個(gè),則這個(gè)就有了被繼承的所有方法和屬性。我們可以直接使用這些方法和屬性,
    發(fā)表于 07-30 18:08

    python私有變量和私有方法

    python私有變量和私有方法1. 下劃線妙用在 Python ,下劃線可是非常推薦使用的符號:變量名推薦使用下劃線分隔的蛇形命名法魔法方法、構(gòu)造函數(shù)都需要使用雙下劃線對于暫時(shí)用不到的變量值,可以
    發(fā)表于 03-08 16:30

    詳解IO設(shè)備管理之父調(diào)用子類方法的過程

    講下注冊接口 rt_device_register,它 干了2個(gè)活:(1)對上,把父(基rt_object)掛到rtt的對象容器。(2)對本類,初始化自己的屬性。1.2.2 訪問
    發(fā)表于 10-09 15:18

    接口與的相同點(diǎn)與區(qū)別

    由于接口中的所有方法都是抽象方法,實(shí)現(xiàn)接口的非抽象一定要實(shí)現(xiàn)接口中所有的抽象方法。
    發(fā)表于 12-22 10:35 ?4181次閱讀

    Object中有哪一些公共方法

    大家在學(xué)習(xí)java的時(shí)候,一定遇到過Object,因?yàn)樵趈ava單一繼承體系Object是根
    發(fā)表于 03-02 09:57 ?822次閱讀

    C# Object方法 怎樣重寫

    在 C# Object所有的基所有的結(jié)構(gòu)和
    發(fā)表于 03-18 11:51 ?1208次閱讀

    SystemVerilog的繼承

    繼承是基于的面向?qū)ο缶幊?object-oriented pro - gramming)的最重要特性之一。
    的頭像 發(fā)表于 11-15 09:47 ?1217次閱讀

    Qt“靈魂”之Meta-Object系統(tǒng)

    Meta-Object即是Qt的元對象系統(tǒng),下文都以元對象系統(tǒng)進(jìn)行描述。在Qt,具有標(biāo)志性特征的則是信號和槽函數(shù)機(jī)制,該機(jī)制的背后實(shí)現(xiàn)本質(zhì)上則是元對象系統(tǒng)。編寫Qt代碼的時(shí)候,在定義的時(shí)候,需要放置一個(gè)Q_
    的頭像 發(fā)表于 02-10 13:50 ?2743次閱讀

    圖解Java多線程的wait()和notify()方法

    wait()和notify()是Object方法,用于線程的等待與喚醒,必須搭配synchronized 鎖來使用。
    的頭像 發(fā)表于 03-22 09:29 ?4284次閱讀

    javaequals()方法的注意事項(xiàng)

    Java的equals()方法是用于比較兩個(gè)對象是否相等的方法。這個(gè)方法是在Object
    的頭像 發(fā)表于 11-17 16:59 ?1279次閱讀

    instanceof在java的用法

    是用來進(jìn)行類型檢查和類型轉(zhuǎn)換。在Java,所有都繼承自Object,因此可以說所有的對象
    的頭像 發(fā)表于 11-21 10:25 ?3085次閱讀

    javaobj類型的實(shí)戰(zhàn)用法

    Java的obj類型是Java中所有的根,它是所有的父
    的頭像 發(fā)表于 11-21 10:27 ?1120次閱讀

    this可以出現(xiàn)在方法

    是的, this 關(guān)鍵字可以出現(xiàn)在方法。在Java, this 是一個(gè)引用,用于引用當(dāng)前對象的實(shí)例。它可以在的實(shí)例
    的頭像 發(fā)表于 11-28 16:24 ?1956次閱讀