首頁技術(shù)文章正文

Java的Object類及其主要方法

更新時(shí)間:2018-10-19 來源:黑馬程序員技術(shù)社區(qū) 瀏覽量:

Object類介紹

Object類位于java.lang包,是所有Java類的根父類(唯一沒有父類的類),所有類的直接或者間接父類。Java中的每個(gè)類都是由這個(gè)類擴(kuò)展而來。

java.lang包在使用的時(shí)候無需顯示導(dǎo)入,編譯時(shí)由編譯器自動(dòng)導(dǎo)入。

Java認(rèn)為所有的對象都具備一些基本的共性內(nèi)容,這些內(nèi)容可以不斷的向上抽取,最終就抽取到了一個(gè)最頂層的類中的,該類中定義的就是所有對象都具備的功能。

如果在類的聲明中未使用extends關(guān)鍵字指明其父類,則默認(rèn)父類為Object類。 

public class Test [extends Object]{ // 默認(rèn)繼承了Object類
    //...
}


接收任意引用類型的對象

既然Object類是所有對象的父類,則肯定所有的對象都可以向Object進(jìn)行轉(zhuǎn)換,在這其中也包含了數(shù)組和接口類型,即:一切的引用數(shù)據(jù)類型都可以使用Object進(jìn)行接收。

使用Object接收接口實(shí)例:

public class Test {
    public static void main(String[] args) {
        A ab = new B() ; // 為接口實(shí)例化
        Object obj = ab ; // 對象向上轉(zhuǎn)型
        A a = (A)obj ; // 對象向下轉(zhuǎn)型
        a.print();
    }
}
interface A { // 定義接口A
    public void print() ; // 定義抽象方法
}
class B implements A { // 子類實(shí)現(xiàn)接口
    public void print(){ // 覆寫接口中的抽象方法
        System.out.println("test") ;
    }
}
使用Object接收數(shù)組:

public class Test {
    public static void main(String[] args) {
        int[] array = {1, 3, 5, 7, 9} ; // 定義數(shù)組
        Object obj = array ; // 使用Object接收數(shù)組
        print(obj) ; // 傳遞數(shù)組引用
    }
    public static void print(Object o){ // 接收一個(gè)對象
        if(o instanceof int[]) { // 判斷對象的類型
            int x[] = (int[])o ; // 向下轉(zhuǎn)型
            for(int i=0;i<x.length;i++){ // 循環(huán)輸出
                System.out.print(x + "\t") ;
            }
        }
    }
}


Object的主要方法

Object類中定義了一些有用的方法,由于是根類,所以這些方法都在其他類中存在,一般是進(jìn)行了重載或者覆蓋,實(shí)現(xiàn)了各自自己的具體功能。



public boolean equals(Object obj)

Object類中的equlas()方法用來檢測兩個(gè)對象是否等價(jià),查看Object源碼為:

public boolean equals(Object obj) {
    return (this == obj);
}
equals()只能比較引用類型,其作用與“==”相同,比較是否指向同一個(gè)對象(其實(shí)內(nèi)部比較的就是兩個(gè)對象地址)。對象比較的是引用,即對象在內(nèi)存中的內(nèi)存地址,而基本數(shù)據(jù)類型比較的是值。

用“==”進(jìn)行比較時(shí),符號(hào)兩邊的數(shù)據(jù)類型必須兼容(可自動(dòng)轉(zhuǎn)換的基本數(shù)據(jù)類型除外),否則編譯出錯(cuò)。



equals()方法需要具有如下特點(diǎn):

自反性(reflexive):任何非空引用x,x.equals(x)返回為true。

對稱性(symmetric):任何非空引用x和y,x.equals(y)返回true當(dāng)且僅當(dāng)y.equals(x)返回true。

傳遞性(transitive):任何非空引用x和y,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)返回true。

一致性(consistent):兩個(gè)非空引用x和y,x.equals(y)的多次調(diào)用應(yīng)該保持一致的結(jié)果,(前提條件是在多次比較之間沒有修改x和y用于比較的相關(guān)信息)。

約定:對于任何非空引用x,x.equals(null)應(yīng)該返回為false。

Student s1 = new Student(); 
Student s2 = new Student();
System.out.println(s1 == s2);   // false
Student s3 = s1;
System.out.println(s3 == s1);   // true
System.out.println(s1.equals(s2));  // false
System.out.println(s1.equals(s1));  // true
System.out.println(s1.equals(s3));  // true
當(dāng)用equals()方法進(jìn)行比較時(shí),對類File、String、Date及包裝類(Wrapper Class)來說,是比較類型及內(nèi)容而不考慮引用的是否是同一個(gè)對象;因?yàn)樵谶@些類中重寫了Object類的equals()方法。下面就是String重寫的equals()方法:

// 重寫了Object類中的equlas()方法    
public boolean equals(Object anObject) {
    // 判斷兩個(gè)字符串的內(nèi)存地址是否相等,如果相等,就說明這兩個(gè)字符串是同一個(gè)
    if (this == anObject) {
        return true;
    }
    // 判斷參數(shù)對象是不是String類型的
    if (anObject instanceof String) {
        // 如果是,就向上轉(zhuǎn)型成一個(gè)String對象
        String anotherString = (String)anObject;
        // 對字符串逐個(gè)字符進(jìn)行比較,每個(gè)字符都相等,返回true
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1 != v2)
                    return false;
                    i++;
            }
            return true;
        }
    }
    return false;
}


public int hashCode()

返回該對象的哈希碼值。哈希值是根據(jù)哈希算法計(jì)算出來的一個(gè)值。這個(gè)值和地址值有關(guān),但不是實(shí)際地址值。

該方法用于哈希查找,可以減少在查找中使用equals的次數(shù),重寫了equals方法一般都要重寫hashCode方法。這個(gè)方法在一些具有哈希功能的Collection中用到。

一般必須滿足obj1.equals(obj2)==true,可以推出obj1.hashCode()==obj2.hashCode(),但是hashCode相等不一定就滿足equals。不過為了提高效率,應(yīng)該盡量使上面兩個(gè)條件接近等價(jià)。如果不重寫hashcode(),在HashSet中添加兩個(gè)equals的對象,會(huì)將兩個(gè)對象都加入進(jìn)去。

// 對象不同,哈希值一般也不同
Student s1 = new Student();
System.out.println(s1.hashCode()); // 366712642
Student s2 = new Student();
System.out.println(s2.hashCode());  // 1829164700
System.out.println("-------");


public final Class getClass()

返回Object運(yùn)行時(shí)類,也就是說是字節(jié)碼文件對象。

不可重寫,要調(diào)用的話,一般和getName()聯(lián)合使用,如getClass().getName()。

Student s = new Student();
// getClass方法會(huì)返回一個(gè)Class類的實(shí)例對象,然后調(diào)用Class類的getName()方法返回全路徑名
System.out.println(s.getClass().getName());  // com.zwj.objectdemo.Student


public String toString()

Object 類的 toString 方法返回一個(gè)字符串,該字符串由類名(對象是該類的一個(gè)實(shí)例)、at 標(biāo)記符“@”和此對象哈希碼的無符號(hào)十六進(jìn)制表示組成。換句話說,該方法返回一個(gè)字符串,它的值等于: getClass().getName() + ‘@’ + Integer.toHexString(hashCode())

// toString方法:返回對象的字符串表示
System.out.println(s.toString());  // com.zwj.objectdemo.Student@7852e922
//直接輸出對象的名稱其實(shí)就是調(diào)用了對象的toString方法
System.out.println(s);   //com.zwj.objectdemo.Student@7852e922


protected void finalize()

當(dāng)垃圾回收器確定不存在對該對象的更多引用時(shí),由對象的垃圾回收器調(diào)用此方法,用于垃圾回收。但是具體什么時(shí)間調(diào)用此方法不確定。 

Java允許在類中定義一個(gè)名為finalize()的方法。它的工作原理是:一旦垃圾回收器準(zhǔn)備好釋放對象占用的存儲(chǔ)空間,將首先調(diào)用其finalize()方法。并且在下一次垃圾回收動(dòng)作發(fā)生時(shí),才會(huì)真正回收對象占用的內(nèi)存。

關(guān)于垃圾回收,有三點(diǎn)需要記住:

1)對象可能不被垃圾回收。只要程序沒有瀕臨存儲(chǔ)空間用完的那一刻,對象占用的空間就總也得不到釋放。

2)垃圾回收并不等于“析構(gòu)”。

3)垃圾回收只與內(nèi)存有關(guān)。使用垃圾回收的唯一原因是為了回收程序不再使用的內(nèi)存。

finalize()的用途:

無論對象是如何創(chuàng)建的,垃圾回收器都會(huì)負(fù)責(zé)釋放對象占據(jù)的所有內(nèi)存。這就將對finalize()的需求限制到一種特殊情況,即通過某種創(chuàng)建對象方式以外的方式為對象分配了存儲(chǔ)空間。

不過這種情況一般發(fā)生在使用“本地方法”的情況下,本地方法是一種在Java中調(diào)用非Java代碼的方式。



protected Object clone()

創(chuàng)建并返回此對象的一個(gè)副本,需要重寫該方法。

要克隆的類去實(shí)現(xiàn)Cloneable接口 ,Cloneable接口是標(biāo)記接口,實(shí)現(xiàn)該接口的類就可以實(shí)現(xiàn)對象的復(fù)制。

public class Student implements Cloneable{
    private String name; // 姓名

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
我們來測試一下:

public class StudentTest{
    public static void main(String[] args) throws CloneNotSupportedException {
        // 創(chuàng)建顯示對象
        Student s = new Student();
        s.setName("zwj");      
        // 克隆學(xué)生對象
        Student cloneStu = (Student) s.clone();
        // 引用
        Student s2 = s;
        System.out.println(s.getName());   // zwj,
        System.out.println(cloneStu.getName());  // zwj
        System.out.println(s2.getName());   // zwj

        s2.setName("爪哇菌");
        System.out.println(s.getName());   // 爪哇菌
        System.out.println(cloneStu.getName());  // zwj
        System.out.println(s2.getName());  // 爪哇菌
    }
}
由以上代碼代碼可以看出Clone()方法的使用比較簡單,使用時(shí)注意如下幾點(diǎn)即可:

什么時(shí)候使用shallow Clone,什么時(shí)候使用deep Clone,這個(gè)主要看具體對象的域是什么性質(zhì)的,基本型別還是reference variable。

調(diào)用Clone()方法的對象所屬的類必須實(shí)現(xiàn)(implements )Clonable接口,否則在調(diào)用Clone方法的時(shí)候會(huì)拋出CloneNotSupportedException。
--------------------- 
【轉(zhuǎn)載】
作者:下班后的爪哇菌 
原文:https://blog.csdn.net/lxxiang1/a ... 874?utm_source=copy

本文版權(quán)歸黑馬程序員JavaEE培訓(xùn)學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明作者出處。謝謝!

作者:黑馬程序員JavaEE培訓(xùn)學(xué)院
首發(fā):http://java.itcast.cn/?skc





分享到:
在線咨詢 我要報(bào)名
和我們在線交談!