亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java中對象的克隆詳解

 更新時間:2023年08月02日 08:51:49   作者:王雀躍  
這篇文章主要介紹了Java中對象的克隆詳解,Java中對象的復制分為淺復制與深復制的不同之處就在于深復制還會復制對象的引用對象,需要的朋友可以參考下

Java對象克隆(復制)

假如想復制一個簡單變量。很簡單:

int apples = 5;
int pears = apples;

不僅int類型,其它七種原始數(shù)據(jù)類型(boolean,char,byte,short,float,double.long)同樣適用于該類情況。

但是如果你復制的是一個對象,情況就復雜了。

假設說我是一個beginner,我會這樣寫:

class Student {  
    private int number;  
    public int getNumber() {  
        return number;  
    }  
    public void setNumber(int number) {  
        this.number = number;  
    }  
}  
public class Test {  
    public static void main(String args[]) {  
        Student stu1 = new Student();  
        stu1.setNumber(12345);  
        Student stu2 = stu1;  
        System.out.println("學生1:" + stu1.getNumber());  
        System.out.println("學生2:" + stu2.getNumber());  
    }  
} 

結(jié)果:

學生1:12345  

學生2:12345  

這里自定義學生類,該類只有number字段。

我們新建了一個學生實例,然后將該值賦值給stu2實例。(Student stu2 = stu1;)

再看看打印結(jié)果,作為一個新手,拍了拍胸腹,對象復制不過如此,

難道真的是這樣嗎?

我們試著改變stu2實例的number字段,再打印結(jié)果看看:

stu2.setNumber(54321);  
System.out.println("學生1:" + stu1.getNumber()); // 學生1:54321  
System.out.println("學生2:" + stu2.getNumber()); // 學生2:54321  

為什么改變學生2的學號,學生1的學號也發(fā)生變化?

原因出在(stu2 = stu1) 這一句。該語句是將stu1的引用賦值給stu2,

這樣,stu1和stu2指向內(nèi)存堆中同一個對象。如圖:

那么,怎樣才能達到復制一個對象呢?

是否記得萬類之王Object。它有11個方法,有兩個protected的方法,其中一個為clone方法。

在Java中所有的類都是繼承自Java語言包中的Object類的,查看它的源碼,發(fā)現(xiàn)里面有一個訪問限定符為protected的方法clone():

/*
Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.
The general intent is that, for any object x, the expression:
1) x.clone() != x will be true
2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.
3) x.clone().equals(x) will be true, this is not an absolute requirement.
*/
protected native Object clone() throws CloneNotSupportedException;

仔細一看,它還是一個native方法,大家都知道native方法是非Java語言實現(xiàn)的代碼,供Java程序調(diào)用的,因為Java程序運行在JVM虛擬機上,要想訪問比較底層與操作系統(tǒng)相關的就沒辦法,只能由靠近操作系統(tǒng)的語言來實現(xiàn)。

  1. 第一次聲明保證克隆對象將有單獨的內(nèi)存地址分配。
  2. 第二次聲明表明,原始和克隆的對象應該具有相同的類類型,但它不是強制性的。
  3. 第三聲明表明,原始和克隆的對象應該是平等的equals()方法使用,但它不是強制性的。

因為每個類直接或間接的父類都是Object,因此它們都含有clone()方法,但是因為該方法是protected,所以都不能在類外進行訪問。

要想對一個對象進行復制,就需對clone方法覆蓋。

為什么要克???

為什么需要克隆對象?直接new一個對象不行嗎?

答案是:克隆的對象可能包含一些已修改過的屬性,而new出來的對象的屬性都是初始化時的值,所以當需要一個新的對象來保存當前對象的“狀態(tài)”就靠clone方法。

那把這個對象的臨時屬性一個個賦值給新new的對象不也行嘛?可以是可以,但是一來麻煩不說,二來,通過上面的源碼都發(fā)現(xiàn)clone是一個native方法,就是快,在底層實現(xiàn)。

提個醒,我們常見的Object a=new Object();Object b;b=a;這種形式的代碼復制的是引用,即對象在內(nèi)存中的地址,a和b對象仍指向同一個對象。

而通過clone方法賦值的對象跟原來的對象是同時獨立存在的。

如何實現(xiàn)克隆

介紹下兩種不同的克隆方法,淺克隆(ShallowClone)深克隆(DeepClone)

Java語言中,數(shù)據(jù)類型分為值類型(基本數(shù)據(jù)類型)和引用類型,值類型包括int、double、byte、boolean、char等簡單數(shù)據(jù)類型,引用類型包括類、接口、數(shù)組等復雜類型。淺克隆和深克隆的主要區(qū)別在于是否支持引用類型的成員變量的復制,下面將對兩者進行詳細介紹。

一般步驟是(淺克?。?/p>

1. 被復制的類需實現(xiàn)Clonenable接口(不實現(xiàn)的話在調(diào)用clone方法會拋出CloneNotSupportedException異常), 該接口為標記接口(不含任何方法)

2. 覆蓋clone()方法,訪問修飾符設為public方法中調(diào)用super.clone()方法得到需要的復制對象。(native為本地方法)

下面對上面那個方法進行改造:

class Student implements Cloneable{  
    private int number;  
    public int getNumber() {  
        return number;  
    }  
    public void setNumber(int number) {  
        this.number = number;  
    }  
    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return stu;  
    }  
}  
public class Test {  
    public static void main(String args[]) {  
        Student stu1 = new Student();  
        stu1.setNumber(12345);  
        Student stu2 = (Student)stu1.clone();  
        System.out.println("學生1:" + stu1.getNumber()); // 學生1:12345  
        System.out.println("學生2:" + stu2.getNumber()); // 學生2:12345  
        stu2.setNumber(54321);  
        System.out.println("學生1:" + stu1.getNumber()); // 學生1:12345  
        System.out.println("學生2:" + stu2.getNumber()); // 學生2:54321
    }  
} 

如果還不相信這兩個對象不是同一個對象,可以看看這一句:

System.out.println(stu1 == stu2); // false  

上面被稱為淺克隆。

還有一種復雜的深度復制:

我們在學生類里再加一個Address類。

class Address  {
    private String add;
    public String getAdd() {
        return add;
    }
    public void setAdd(String add) {
        this.add = add;
    }
}
class Student implements Cloneable{
    private int number;
    private Address addr;
    public Address getAddr() {
        return addr;
    }
    public void setAddr(Address addr) {
        this.addr = addr;
    }
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    @Override
    public Object clone() {
        Student stu = null;
        try{
            stu = (Student)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return stu;
    }
}
public class Test {
    public static void main(String args[]) {
        Address addr = new Address();
        addr.setAdd("杭州市");
        Student stu1 = new Student();
        stu1.setNumber(123);
        stu1.setAddr(addr);
        Student stu2 = (Student)stu1.clone();
        System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
        System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
    }
}

結(jié)果:

學生1:123,地址:杭州市  
 
學生2:123,地址:杭州市

乍一看沒問題,真的是這樣嗎?在main方法中改變addr實例的地址。

addr.setAdd("西湖區(qū)");  
System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  

結(jié)果:

學生1:123,地址:杭州市  
學生2:123,地址:杭州市  
學生1:123,地址:西湖區(qū)  
學生2:123,地址:西湖區(qū) 

這就奇怪了,怎么兩個學生的地址都改變了?

原因是淺復制只復制addr變量的引用,并沒有真正的開辟另一塊空間,將值復制后再將引用返回給新對象。

所以,為了達到真正的復制對象,而不是純粹引用復制。需要將Address類可復制化,并且修改clone方法,完整代碼如下:

class Address implements Cloneable {
    private String add;
    public String getAdd() {
        return add;
    }
    public void setAdd(String add) {
        this.add = add;
    }
    @Override
    public Object clone() {
        Address addr = null;
        try{
            addr = (Address)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return addr;
    }
}
class Student implements Cloneable{
    private int number;
    private Address addr;
    public Address getAddr() {
        return addr;
    }
    public void setAddr(Address addr) {
        this.addr = addr;
    }
    public int getNumber() {
        return number;
    }
    public void setNumber(int number) {
        this.number = number;
    }
    @Override
    public Object clone() {
        Student stu = null;
        try{
            stu = (Student)super.clone();   //淺復制
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        stu.addr = (Address)addr.clone();   //深度復制
        return stu;
    }
}
public class Test {
    public static void main(String args[]) {
        Address addr = new Address();
        addr.setAdd("杭州市");
        Student stu1 = new Student();
        stu1.setNumber(123);
        stu1.setAddr(addr);
        Student stu2 = (Student)stu1.clone();
        System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
        System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
        addr.setAdd("西湖區(qū)");
        System.out.println("學生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
        System.out.println("學生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
    }
}

結(jié)果:

學生1:123,地址:杭州市  
學生2:123,地址:杭州市  
學生1:123,地址:西湖區(qū)  
學生2:123,地址:杭州市

到此這篇關于Java中對象的克隆詳解的文章就介紹到這了,更多相關Java對象克隆內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java Online Exam在線考試系統(tǒng)的實現(xiàn)

    Java Online Exam在線考試系統(tǒng)的實現(xiàn)

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+springboot+vue+jsp+mysql+maven實現(xiàn)Online Exam在線考試系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • Java實現(xiàn)去掉字符串重復字母的方法示例

    Java實現(xiàn)去掉字符串重復字母的方法示例

    這篇文章主要介紹了Java實現(xiàn)去掉字符串重復字母的方法,涉及java針對字符串的遍歷、判斷、運算等相關操作技巧,需要的朋友可以參考下
    2017-12-12
  • Java實現(xiàn)多項式除法的代碼示例

    Java實現(xiàn)多項式除法的代碼示例

    今天小編就為大家分享一篇關于Java實現(xiàn)多項式除法的代碼示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式

    SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式

    在Web應用程序開發(fā)中,統(tǒng)一數(shù)據(jù)返回格式對于前后端分離項目尤為重要,本文就來介紹一下SpringBoot統(tǒng)一數(shù)據(jù)返回的幾種方式,具有一定的參考價值,感興趣的可以了解一下
    2024-07-07
  • HttpClient實現(xiàn)調(diào)用外部項目接口工具類的示例

    HttpClient實現(xiàn)調(diào)用外部項目接口工具類的示例

    下面小編就為大家?guī)硪黄狧ttpClient實現(xiàn)調(diào)用外部項目接口工具類的示例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Java?8?中?Function?接口使用方法介紹

    Java?8?中?Function?接口使用方法介紹

    這篇文章主要介紹了Java?8中?Function接口使用方法介紹,Java8中提供了一個函數(shù)式接口Function,這個接口表示對一個參數(shù)做一些操作然后返回操作之后的值
    2022-06-06
  • Java實現(xiàn)隨機驗證碼具體代碼

    Java實現(xiàn)隨機驗證碼具體代碼

    這篇文章主要為大家詳細介紹了Java實現(xiàn)隨機驗證碼具體代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Java基于字符界面的簡易收銀臺

    Java基于字符界面的簡易收銀臺

    這篇文章主要為大家詳細介紹了Java基于字符界面的簡易收銀臺,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • java中Swing五種常見的布局方式

    java中Swing五種常見的布局方式

    本文通過代碼示例給大家詳細講解了java中Swing五種常見的布局方式,以及相關注意知識點,有興趣的朋友參考學習下。
    2018-03-03
  • javaweb 項目初始配置的方法步驟

    javaweb 項目初始配置的方法步驟

    本文主要介紹了javaweb 項目初始配置的方法步驟,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11

最新評論