欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文帶你認(rèn)識Java中的Object類和深淺拷貝

 更新時間:2023年04月23日 09:48:29   作者:牛牛要堅持  
任何變成語言中,其實都有淺拷貝和深拷貝的概念,Java 中也不例外,下面這篇文章主要給大家介紹了關(guān)于Java中Object類和深淺拷貝的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

本文介紹了Object類以及Object類部分方法,toString方法,equals和hashCode方法(重寫前和重寫后的對比),getClass方法,clone方法,以及拷貝新對象時會出現(xiàn)的深淺拷貝,內(nèi)容較長,耗時一天,建議收藏后觀看~

一.初識Object類

Object類是Java默認(rèn)提供的一個類。而這個類是Java里所有類的頂級父類,即在繼承體系下,除了Object以外的所有類都可能有自己的父類,但Object類沒有父類,
并且所有的類同時也都默認(rèn)繼承Object類…
Object類是在Java.lang 包中的,默認(rèn)已經(jīng)導(dǎo)入了此類

有了Object類,可以使方法的形參接受任何類的對象,也可以使返回類型返回任意類的對象,可以使所有類都繼承一些Object共有的方法,故Object類是非常重要的類!!!

1.Object類接收所有子類實例

也就是說,不管是Java庫里的類還是自己定義的類,不管它們是否有自己的父類,都默認(rèn)繼承著Object類…

Object類的存在,使所有類之間有了聯(lián)系,根據(jù)向上轉(zhuǎn)型的用法:父類引用可以接收子類對象地址…

那么就可以使用Object類型的引用接受所有類的實例對象

示例:

class Student{//自定義學(xué)生類
    String name;
    Student(String name){
        this.name=name;
    }
}
class Animal{//自定義動物類
    String name;
    Animal(String name){
        this.name=name;
    }
}
public class Text {


    public static void function(Object obj) {
        System.out.println(obj);
    }

    public static void main(String[] args) {
        function(new Animal("動物"));
        function(new Student("學(xué)生"));
    }
}

Person和Animal類都是自定義的類,其沒有extends顯示繼承其他類,但也默認(rèn)繼承Object類,那么可以通過調(diào)用function方法形參用Object類型的引用obj接受每個對象,而此時發(fā)生向上轉(zhuǎn)型,而通過輸出方法println輸出obj,最后輸出了兩個對象的內(nèi)容!!

思考:

通過傳遞的對象不同,輸出的內(nèi)容也不同,那這種實現(xiàn)是否是多態(tài)呢?

多態(tài)即調(diào)用同一方法但不同對象會體現(xiàn)出不同的狀態(tài),這里看似是不同狀態(tài),但是多態(tài)實現(xiàn)條件沒有滿足,因為并沒有發(fā)生重寫和動態(tài)綁定

輸出的內(nèi)容本應(yīng)是每個對象的名字,但為什么會是一堆字母串?

以demo6.Animal@1b6d3586為例 demo6.Animal即是類的全路徑(包名+類名)
@是分隔符, 而1b6d3586是一串十六進(jìn)制數(shù)的字符可以暫時理解為對象的地址

那println方法底層是怎么輸出這些的呢?

下面是println的一些源碼分析:

此方法是用Object 類型引用接受 即可以接收任意類的實例,即所有對象都能輸出

可見最關(guān)鍵的是String.valueOf方法,即是將對象內(nèi)容轉(zhuǎn)換為字符串形式

再進(jìn)入到此方法進(jìn)行分析↓

valueOf方法 返回的即是對象的字符串形式,而當(dāng)obj接受的是null時,直接返回null

當(dāng)不為空時,即通過toString方法獲取到對象的內(nèi)容的字符串形式返回…

重點(diǎn)來了:

toString方法在定義Person,和Animal時并沒有寫此方法,而這兩個類也沒有顯示繼承任何的類,而obj指向的對象是Person或者Animal,說明toString方法只能是Object類里面的

故這兩個類沒有重寫toString方法,也就沒有發(fā)生動態(tài)綁定,調(diào)用和執(zhí)行的一直是Object類的toString方法,故也沒有發(fā)生多態(tài)

簡單了解 在Object類里的toString方法

getClass()是獲取到Person或者Animal的類示例,.然后getName()獲取到其類所在的全路徑的以字符串形式返回

@是分隔符
hashCode()得到的是Person或者Animal實例的hash值,是一個整數(shù)(主要用于區(qū)分不同的對象,但可能會存在不同的對象hash值相同的情況(哈希沖突) )

而Integer.toHexString方法即是將獲取到的hash值轉(zhuǎn)換為十六進(jìn)制的字符串形式

以此最后得到類似于demo6.Animal@1b6d3586 這種輸出格式

注意: hashCode 和getClass()底層都是native修飾的本地方法,底層由C或者C++代碼實現(xiàn),先明白此方法的大概用途即可

2.Object類部分方法介紹

Object是所有類的父類,其內(nèi)部定義了一些成員方法,這些方法都會被子類繼承,一些通常會被子類重寫來使用,學(xué)會使用這些方法是很有必要的

以下是Object內(nèi)的成員方法簡單介紹,

簡單介紹下被圈起來的成員方法,而其他的方法需要在線程方面用到…

①.Object內(nèi)的toString方法

toString方法主要就是針對對象的內(nèi)容,即將對象的內(nèi)容轉(zhuǎn)換成字符串形式返回

在上面介紹到,當(dāng)想輸出某個對象內(nèi)容可以通過調(diào)用println輸出方法,println方法的形參是Object類型接受,然后會調(diào)用String.valueOf方法 將對象內(nèi)容轉(zhuǎn)換為字符串,而此方法內(nèi)會調(diào)用toString方法,最后輸出的是:類的全路徑@hashCode的十六進(jìn)制形式

但是這并不符合我們想要輸出的對象內(nèi)容,當(dāng)Person對象和Animal對象想要輸出的內(nèi)容是對象內(nèi)的成員變量name要怎么做?

此時就要重寫toString方法↓

1.可以根據(jù)Objec里的toString的方法在對應(yīng)的子類里寫同樣的權(quán)限修飾符返回值類型 方法名(需滿足重寫的要求) 然后具體方法體根據(jù)自己實現(xiàn)

public String toString(){

  //重寫的內(nèi)容...
}

2.使用IDEA快捷鍵或者右擊,選擇Generate ->toString 自動生成重寫的toString

@Override
    public String toString() {
        return "Animal{" +   //自動生成的內(nèi)容  ,也可以根據(jù)需求自己修改
                "name='" + name + '\'' +
                '}';
    }

當(dāng)在Person和Animal類里重寫了toString方法后,再次調(diào)用上面function方法其內(nèi)部輸出obj接受的對象內(nèi)容即能輸出每個對象的指定內(nèi)容

class Animal{
    String name;
    Animal(String name){
        this.name=name;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student {
    String name;

    Student(String name) {
        this.name = name;
    }

    @Override
    public String toString() {  //重寫內(nèi)容
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

}
public class Text {


    public static void function(Object obj) {
        System.out.println(obj);
    }

    public static void main(String[] args) {
        function(new Animal("動物"));
        function(new Student("學(xué)生"));
    }
 }

obj接受Person或者Animal對象,調(diào)用println方法,而內(nèi)部最后會調(diào)用Object類里的toString方法得到對象內(nèi)容的字符串形式,但是因為發(fā)生了子類重寫Object類的toString方法

此時調(diào)用Object類的toString方法執(zhí)行的是子類自己重寫的Object類的toString方法(多態(tài))

而Person和Animal兩個類都重寫了toString,此時則發(fā)生了多態(tài)…

最后根據(jù)自己設(shè)置的對象內(nèi)容輸出了對應(yīng)的對象…

總結(jié):

toString沒有重寫時輸出的是對象其類的全路徑@十六進(jìn)制形式的hashCode值
toString重寫時輸出的是自己重寫的指定對象內(nèi)容 (更常用)

②.Object內(nèi)的equals和hashCode方法

equals是比較當(dāng)前對象和指定對象是否相等,hashCode是獲取當(dāng)前對象的哈希值
二者通常是成對出現(xiàn)的!

1.Object內(nèi)的equals方法和hashCode方法

Object內(nèi)的equals方法:

this引用表示當(dāng)前對象的引用存放的當(dāng)前對象的地址,而obj引用接受的是要比較的對象的地址…

故Object內(nèi)的equals方法比較兩個對象時,比較的是兩個對象的地址,而對象不同則對象地址一定是不相等,即絕大部分返回的值都是false

而我們大部分情況下判斷對象是否相等并不是看對象地址,而是看對象的內(nèi)容是否相等(成員變量內(nèi)的值),

要實現(xiàn)這種要求,就要重寫equals方法! (根據(jù)內(nèi)容比較對象是否相等)

Object內(nèi)的hashCode方法:

此方法是native修飾的本地方法,無法直接看到源碼.但大致就是通過對象地址根據(jù)對應(yīng)規(guī)則生成一個整數(shù)即哈希值

簡單了解hashCode的用途:

hashCode方法在作用在哈希桶處體現(xiàn),所謂哈希桶就是一個鏈表數(shù)組,用來動態(tài)的搜索數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu).,主要作用用來搜索 故哈希桶內(nèi)相同的對象只會存放一份!

當(dāng)你要存放對象在哈希桶內(nèi)時,即是對應(yīng)到數(shù)組某個下標(biāo)的空間內(nèi)存放該對象,而對象怎么得到一個整形下標(biāo),即是通過了hashCode方法生成的一個整數(shù),最后通過該整數(shù)與數(shù)組長度取余映射到數(shù)組的對應(yīng)下標(biāo)!

但是hashCode生成的整數(shù)跟對象地址有關(guān),那么不同對象會生成不同的整數(shù),但是實際情況判斷一個對象是否相同不是看對象地址,而是看對象內(nèi)容,當(dāng)內(nèi)容完全一樣,而hashCode又不同,會發(fā)生在一個哈希桶內(nèi)存放著兩個內(nèi)容一樣的對象,

或者當(dāng)又new了一個新對象其內(nèi)容和之前對象完全相同,可是通過調(diào)用hashCode方法根據(jù)對象地址生成的哈希值不同映射到不同數(shù)組下標(biāo),而在此下標(biāo)對應(yīng)的空間內(nèi)又沒有找到和之前對象內(nèi)容完全相同的,則會出現(xiàn)在哈希桶內(nèi)查找對象時,找不到內(nèi)容相同的對象但是哈希桶內(nèi)又存在這樣的對象,則達(dá)不到我們所實現(xiàn)的要求…

而要實現(xiàn)映射的數(shù)組下標(biāo)即要使獲得的hashCode相同,那么就要重寫hashCode方法(根據(jù)對象內(nèi)容生成哈希值)

===============================================================

2.重寫equals方法和hashCode方法

上面介紹在Object內(nèi)的equals方法和hashCode方法不滿足實際需求,此時需要在子類里根據(jù)實際需求重寫這兩個方法,重寫之后即會實現(xiàn)動態(tài)綁定 調(diào)用我們重寫的方法

重寫equals方法和hashCode方法可以根據(jù)其Object內(nèi)的方法在子類里寫滿足重寫要求的方法,方法體根據(jù)自己需求而改, 要考慮實際情況重寫,hashCode也要自己定一套根據(jù)不同內(nèi)容生成對應(yīng)的整數(shù)的哈希方法

而在IDEA里提供了快捷生成的重寫方法,右擊 Generate 點(diǎn)擊equals and hashCode 一路Next即可 自動根據(jù)對象內(nèi)容生成 equals方法和hashCode方法

@Override
    public boolean equals(Object o) {
        if (this == o) return true;// 對象地址相等返回true
        if (o == null || getClass() != o.getClass()) 
        return false; 要比較的對象為null或者 兩個對象是不同的類實例 返回false
        
        Animal animal = (Animal) o;
        return Objects.equals(name, animal.name);
        //根據(jù)Objects類的equals方法 傳指定內(nèi)容比較是否相等返回結(jié)果
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);//根據(jù)Objects類的hash方法傳指定參數(shù) 即根據(jù)其參數(shù)內(nèi)容生成hashCode
    }

自動生成的equals方法和hashCode方法底層都調(diào)用了Objects類的方法,而Objects類即是Object類的api,里面提供的都是靜態(tài)方法,主要用于當(dāng)重寫Object類時,根據(jù)子類對象的內(nèi)容調(diào)用Objects對應(yīng)的方法,分化成子類內(nèi)容之間進(jìn)行操作

equals(name, animal.name);

接受當(dāng)前對象的name和指定比較對象的name, 而此時的a.equals(b) 轉(zhuǎn)換為了name之間的比較,而name是String類型,其類已經(jīng)封裝好了對equals的重寫(即判斷每個字符是否相等),通過此方法得出對應(yīng)的內(nèi)容是否相等,當(dāng)有多個參數(shù)比較則會依次調(diào)用多個此方法

===============================================================

Objects.hash(name);

其內(nèi)部的hash方法形參是Object…values

而這個語法叫做可變參數(shù):

在 Java 5 中提供了變長參數(shù),允許在調(diào)用方法時傳入不定長度的參數(shù)。變長參數(shù)是 Java 的一個語法糖,本質(zhì)上還是基于數(shù)組的實現(xiàn):

在定義方法時,在最后一個形參后加上三點(diǎn) …,就表示該形參可以接受多個參數(shù)值,多個參數(shù)值被當(dāng)成數(shù)組傳入。上述定義有幾個要點(diǎn)需要注意:

可變參數(shù)只能作為函數(shù)的最后一個參數(shù),但其前面可以有也可以沒有任何其他參數(shù)

由于可變參數(shù)必須是最后一個參數(shù),所以一個函數(shù)最多只能有一個可變參數(shù)

Java的可變參數(shù),會被編譯器轉(zhuǎn)型為一個數(shù)組

變長參數(shù)在編譯為字節(jié)碼后,在方法簽名中就是以數(shù)組形態(tài)出現(xiàn)的。這兩個方法的簽名是一致的,不能作為方法的重載。如果同時出現(xiàn),是不能編譯通過的??勺儏?shù)可以兼容數(shù)組,反之則不成立

使用了可變參數(shù)說明hash()實參可以有多個,根據(jù)實際情況而定,最后都會被接受放在Object數(shù)組里,此時再調(diào)用其內(nèi)部封裝的hashCode , 按相應(yīng)的規(guī)則,調(diào)用數(shù)組每一個元素的hashCode方法,因為每一個元素都是指定對象的內(nèi)容 可能是字符串類型或者是Integer類型等, 其內(nèi)部都封裝了hashCode方法,有自己根據(jù)自身內(nèi)容生成哈希值的方法,最后合并得到一個哈希值返回給Objects.hash方法調(diào)用方得到一個根據(jù)對象指定內(nèi)容生成的哈希值

故使用編譯器自動生成的重寫equals和hashCode方法,會編寫好相應(yīng)的方法體,在我們使用的時候,根據(jù)需求對對象相應(yīng)內(nèi)容要比較的參數(shù)傳上去,根據(jù)指定內(nèi)容或者全部內(nèi)容以此判斷對象是否相等以及生成相應(yīng)的hash值!

為什么equals和hashCode需要一起重寫?

因為當(dāng)只重寫了equals表示會根據(jù)相應(yīng)內(nèi)容和指定對象進(jìn)行比較是否相等,此時沒有重寫hashCode則在哈希桶里仍然會出現(xiàn)指定內(nèi)容相同的對象出現(xiàn)多份或者有指定內(nèi)容相等的對象但是沒有找到此對象的情況

而只重寫hashCode是沒有意義的…哈希桶里即便出現(xiàn)了對象內(nèi)容完全一樣的,也會因為對象地址不同而判定為兩個不同的對象…
所以二者一定要有關(guān)聯(lián),且要一起重寫…

equals和hashCode的關(guān)系

equals判斷兩個對象相等其hashCode一定相等嘛?

equals判斷兩個對象完全相等,要么地址相等要么指定內(nèi)容相等,對應(yīng)的如果重寫了equals也就會根據(jù)內(nèi)容重寫hashCode 那么hashCode一定會相等

hashCode相等 equals判斷兩個對象一定會相等嘛?

hashCode相等只能說明在指定的獲取哈希的函數(shù)里兩個對象的指定內(nèi)容或者地址最后生成的哈希值是相同的,但是也有可能內(nèi)容地址不同卻出現(xiàn)相同的哈希值(哈希沖突),但是此時equals并不會相同!

總結(jié):

equals相同,hashCode一定相同, hashCode相同 equals不一定相同,

equals不同,hashCode可能相同,hashCode不同則equals一定不相同

③.Object類的getClass方法

getClass方法是Java中獲取類實例的一種方法,而類實例主要用于反射中使用

簡單了解下反射機(jī)制:

Java文件被編譯后,生成了.class文件,JVM此時就要去解讀.class文件
,被編譯后的Java文件.class也被JVM解析為一個對象,這個對象就是 java.lang.Class .
這樣當(dāng)程序在運(yùn)行時,每個java文件就最終變成了Class類對象的一個實例。我們通過Java的反射機(jī)制應(yīng)用到這個實例,就可以去獲得甚至去添加改變這個類的屬性和動作,使得這個類成為一個動態(tài)的類

而一個類文件 只有一個類實例,一個類實例化多個對象,通過這多個對象調(diào)用getClass獲得的類實例都是同一個

在使用快捷命令重寫equals方法生成的代碼中使用了getClass方法,

即是獲得當(dāng)前對象的類實例,

和Object類型的o引用接受的對象調(diào)用getClass獲得的類實例(即o指向的對象的類實例)判斷是否相等,如果是同一個類實例化的對象則獲取的類實例是同一個,如果是不同 的類的實例對象 則會返回false…此處即是為了判斷兩個對象是否是同一個類實例而來

也可以使用 if ( ! o instanceof Person) return false;判斷 o指向的對象是否是Person的實例,從而判斷兩個對象是否是同一個類實例而來

④.Object類的clone方法

Object類里的clone方法是native修飾的本地方法底層由C/C++實現(xiàn)是直接供對象調(diào)用的方法,當(dāng)對象調(diào)用clone方法會在堆區(qū)創(chuàng)建一份和原對象一模一樣的對象返回(即屬性和行為都一樣)

雖然clone方法可以直接調(diào)用,但并不是字面意思上直接調(diào)用

class Person{
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}

當(dāng)有了上面這個類,我們是否可以在main方法中直接創(chuàng)建一份Person對象,再直接調(diào)用clone方法再用一個Person引用接受克隆的新對象呢?

此時會編譯報錯, 在Java中clone被看成一種公共特性,即提供了一個Cloneable接口,其是一個空接口,表示一個標(biāo)準(zhǔn)規(guī)范,只有實現(xiàn)了此接口的類才能調(diào)用clone方法進(jìn)行克隆,如果沒有實現(xiàn),則會報CloneNotSupportedException異常

class Person implements Cloneable{
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}

當(dāng)Person實現(xiàn)了Cloneable具備了克隆特性 是否可以克隆了呢?

注意! clone方法在Object類是protected修飾的!!!

當(dāng)被protected修飾的成員,在當(dāng)前包里可以直接被訪問,但是在不同包里,只能在其對應(yīng)的子類內(nèi)被訪問!

即調(diào)用的是Person對象繼承的Object類的clone方法,Person是Object的子類,那么就要在Person類內(nèi)調(diào)用clone方法,Test類雖然也是Object的子類但是調(diào)用的是Person,所以在Test類里是不能調(diào)用到Person類對象的clone方法

為了實現(xiàn)接口方法統(tǒng)一使在Test類里能夠調(diào)用到Person的clone方法,這里也要在Person類里重寫clone方法,但這個重寫只是給類外提供調(diào)用clone的方法,并沒有重寫clone本身的方法

通過 在Person 里重寫 clone方法 方法體 是調(diào)用其父類Object類的clone方法,但是會拋出一個編譯時異常,此異常為了提醒程序員需要處理此異常,即必須try-catch處理或者throws 聲明異常拋給上層調(diào)用方

使用throws層層聲明異常后↓

到這里最后一步,能夠調(diào)用Person的clone方法 克隆一份一樣的對象,但是clone方法的返回類型是Object類型的,不能直接用Person接受,向下轉(zhuǎn)型需要這里強(qiáng)轉(zhuǎn)

最終的寫法↓

class Person implements Cloneable{//Person實現(xiàn)Cloneable 支持克隆
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Text {//Cloneable是一個接口 空接口 是一個標(biāo)記接口 標(biāo)準(zhǔn)規(guī)范 唯一作用 表示當(dāng)前類實例化的對象是可以被克隆的,如果沒有實現(xiàn)這個接口就不能被克隆
    //實現(xiàn)cloneable接口 當(dāng)前對象可以克隆 但是需要重寫object類的clone方法,但是這個重寫只能為了調(diào)用父類clone方法!!! 沒有實現(xiàn)這兩種會報編譯時異常!

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("張三", 18);
        Person clonePerson = (Person) person.clone();
        
    }

}

為什么clone返回類型是Object類型?

一個方法只有一個返回類型,而實現(xiàn)cloneable接口的對象一般都支持克隆,但是既然可以克隆很多對象,那么返回類型是不確定具體返回的對象類是哪個,而根據(jù)Object類的特性,其是所有類的父類,那么就可以達(dá)成通用, 借助向上轉(zhuǎn)型返回對象,在外層由程序員自己進(jìn)行向下轉(zhuǎn)型 從而實現(xiàn)對應(yīng)的類型接受對應(yīng)的克隆對象

二.認(rèn)識深拷貝和淺拷貝

在認(rèn)識Object的clone方法后,我們能直接拷貝一份和對象一模一樣的新對象出來,但是在拷貝對象時,因為引用變量存放的是對象地址,故在拷貝時還要區(qū)分深拷貝和淺拷貝!

1.什么是深淺拷貝?

淺拷貝即是當(dāng)修改拷貝的對象內(nèi)容時, 原被拷貝對象的內(nèi)容也會隨之被修改,即兩個對象共用同一塊內(nèi)容,看似拷貝了一份全新的對象,但是這個對象的成員和原對象的成員仍然共用同一份空間
深拷貝即當(dāng)修改拷貝對象內(nèi)容時,原拷貝對象內(nèi)容不會改變,即兩個對象的所有內(nèi)容也是獨(dú)立被拷貝的!

class Money implements Cloneable{
    public double m=3.14;

    @Override
    public String toString() {
        return "Money{" +
                "m=" + m +
                '}';
    }
}
public class Student implements Cloneable {
    Money money=new Money();
    public String name;
    public int age=18;
    public Student(String name){
        this.name=name;
    }

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

    @Override
     public String toString() {
        return "Student{" +
                "money=" + money +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public static void main(String[] args) throws CloneNotSupportedException{
        Student student=new Student("666");
        Student student1=(Student) student.clone();
        System.out.println(student);
        System.out.println(student1);
        student1.age=20;// 基本數(shù)據(jù)類型存放的是原對象的數(shù)據(jù) 此時修改基本數(shù)據(jù)類型, 原對象并不會受到影響
        student1.name="000";//name雖然指向的是同一個對象 但是后面直接是實例化另一個對象給克隆的引用變量本質(zhì)上
        // 克隆對象的name一開始指向的和原對象的name指向的字符串對象一樣
        student1.money.m=100.0;   //會克隆一份對象 里面成員變量值和方法是和原對象一樣的
        //引用數(shù)據(jù)類型存放的是原對象的對象地址 這就造成 克隆后對象內(nèi)的引用變量指向的是同一塊對象地址
        //此時通過引用變量修改對象內(nèi)容 原來的和克隆的占用的是同一份 淺拷貝!!! money指向的同一塊對象里面的m成員 共用一塊空間
        System.out.println("更改后===========");
        System.out.println(student);
        System.out.println(student1);
    }

}

通過上面代碼運(yùn)行后 發(fā)現(xiàn) 只對克隆的對象內(nèi)容進(jìn)行修改后,但有些內(nèi)容原對象也跟著改變,這即是發(fā)生淺拷貝, 拷貝的程度淺,對象拷貝了一份但內(nèi)容卻沒有真正拷貝.

age是基本數(shù)據(jù)類型,拷貝的對象內(nèi)也存有一份age數(shù)據(jù),修改這個age不會影響原對象的age值,name是引用類型數(shù)據(jù) 指向字符串對象, 而修改拷貝對象內(nèi)的字符串對象本質(zhì)是創(chuàng)建了一個新字符串,故也沒有影響原對象,

但是Menoy引用指向的一份對象,經(jīng)過拷貝后 新對象的Menoy引用同樣存放著原Menoy對象的地址,此時通過新對象修改Menoy指向的對象內(nèi)的值,原對象內(nèi)的Menoy對象內(nèi)的值也會發(fā)生改變

此時的拷貝形式正是淺拷貝,對象并沒有完全被拷貝,而如何實現(xiàn)深拷貝呢?

2.實現(xiàn)深拷貝

淺拷貝即拷貝了新對象,但是新對象的內(nèi)容可能和原對象共用一塊空間,故要實現(xiàn)深拷貝,要在原來拷貝的基礎(chǔ)上,對可能共用一塊空間的內(nèi)容進(jìn)行再拷貝一份

在上面代碼基礎(chǔ)上,使Menoy引用指向不同對象則要對Menoy對象單獨(dú)進(jìn)行克隆

class Money implements Cloneable{
    public double m=3.14;


    @Override
    public String toString() {
        return "Money{" +
                "m=" + m +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();   //這里用于給 money克隆一份
    }
}
public class Student implements Cloneable {
    Money money=new Money();
    public String name;
    public int age=18;
    public Student(String name){
        this.name=name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        student.money=(Money) this.money.clone(); //調(diào)用 money的clone方法為其克隆出一份 
        return student; //自動向上轉(zhuǎn)型
    }

    @Override
    public String toString() {
        return "Student{" +
                "money=" + money +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

對象內(nèi)主要是Menoy對象是同一個空間,那么在克隆對象時,先克隆出新Student對象,再根據(jù)指定Menoy對象克隆出新的Menoy對象(Menoy也要支持clone)給克隆對象的Menoy引用,最后返回克隆的新對象, 最后實現(xiàn)了深拷貝,兩個對象的內(nèi)容是獨(dú)立不互不影響的

注意: 除了clone能拷貝對象以外還有其他方法能對對象進(jìn)行拷貝,如Arrays.copyOf方法能夠?qū)χ付〝?shù)組對象進(jìn)行拷貝,對數(shù)組進(jìn)行拷貝 也會出現(xiàn)深淺拷貝的現(xiàn)象,拷貝的新數(shù)組每個引用可能指向的原數(shù)組的每個引用指向的對象…

故在拷貝時要注意需要的是深拷貝還是淺拷貝…

三.Object類和深淺拷貝總結(jié)

本篇博客介紹了Object類 以及其內(nèi)部的一些方法:toString(重寫前:獲取其類的全路徑@對象地址,重寫后將對象內(nèi)容轉(zhuǎn)換為字符串形式返回),
equals和hashCode(重寫前:判斷對象的地址是否相等和根據(jù)對象地址生成哈希值,重寫后:判斷對象指定內(nèi)容是否相等和根據(jù)指定內(nèi)容獲取對象生成的哈希值),
getClass (獲取類實例),clone(克隆對象需要注意權(quán)限和異常)
以及跟克隆相關(guān)的深淺拷貝(對新對象內(nèi)容進(jìn)行修改是否會影響原對象的內(nèi)容)

到此這篇關(guān)于Java中的Object類和深淺拷貝的文章就介紹到這了,更多相關(guān)Java Object類和深淺拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • windows下 jdk1.7安裝教程圖解

    windows下 jdk1.7安裝教程圖解

    java編程的初學(xué)者在開始編碼前都會遇到一個難題,那就是jdk1.7環(huán)境變量配置怎么操作,怎么安裝,針對這個難題,小編特地為大家整理相關(guān)教程,不了解的朋友可以前往查看使用
    2018-05-05
  • SWT(JFace)體驗之ApplicationWindow

    SWT(JFace)體驗之ApplicationWindow

    SWT(JFace)體驗之ApplicationWindow
    2009-06-06
  • idea同時編輯多行問題-win&mac都支持

    idea同時編輯多行問題-win&mac都支持

    這篇文章主要介紹了idea同時編輯多行問題-win&mac都支持,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • SpringBoot使用JdbcTemplate訪問操作數(shù)據(jù)庫基本用法

    SpringBoot使用JdbcTemplate訪問操作數(shù)據(jù)庫基本用法

    這篇文章主要介紹了SpringBoot使用JdbcTemplate訪問操作數(shù)據(jù)庫基本用法,Spring對數(shù)據(jù)庫的操作在jdbc上s面做了深層次的封裝,使用spring的注入功能,可以把DataSource注冊到JdbcTemplate之中。下文詳細(xì)內(nèi)容需要的小伙伴可以參考一下
    2022-02-02
  • 詳解Mybatis中的CRUD

    詳解Mybatis中的CRUD

    這篇文章主要介紹了Mybatis中的CRUD的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Spring Boot報錯:No session repository could be auto-configured, check your configuration的解決方法

    Spring Boot報錯:No session repository could be auto-configured

    這篇文章主要給大家介紹了關(guān)于Spring Boot報錯:No session repository could be auto-configured, check your configuration的解決方法,文中給出了詳細(xì)的解決方法,對遇到這個問題的朋友們具有一定參考價值,需要的朋友下面來一起看看吧。
    2017-07-07
  • MybatisPlus+Postgresql整合的幾個坑及解決

    MybatisPlus+Postgresql整合的幾個坑及解決

    這篇文章主要介紹了MybatisPlus+Postgresql整合的幾個坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Spring深入了解常用配置應(yīng)用

    Spring深入了解常用配置應(yīng)用

    這篇文章主要給大家介紹了關(guān)于Spring的常用配置,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用springboot具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2022-07-07
  • Spring實現(xiàn)動態(tài)切換多數(shù)據(jù)源的解決方案

    Spring實現(xiàn)動態(tài)切換多數(shù)據(jù)源的解決方案

    這篇文章主要給大家介紹了Spring實現(xiàn)動態(tài)切換多數(shù)據(jù)源的解決方案,文中給出了詳細(xì)的介紹和示例代碼,相信對大家的理解和學(xué)習(xí)具有一定的參考借鑒價值,有需要的朋友可以參考學(xué)習(xí),下面來一起看看吧。
    2017-01-01
  • 淺談Java注解和動態(tài)代理

    淺談Java注解和動態(tài)代理

    這篇文章主要介紹了Java中有關(guān)注解和動態(tài)代理的一些知識,涉及了Annotation、數(shù)據(jù)類型等相關(guān)內(nèi)容,需要的朋友可以參考下。
    2017-09-09

最新評論