最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)同樣適用于該類情況。

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

假設(shè)說我是一個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)相關(guān)的就沒辦法,只能由靠近操作系統(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()方法,訪問修飾符設(shè)為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,地址:杭州市

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

相關(guān)文章

  • SpringBoot中的異步任務解析

    SpringBoot中的異步任務解析

    這篇文章主要介紹了SpringBoot中的異步任務解析,SpringBoot 異步任務是一種在SpringBoot框架中使用的異步處理機制,可以提高系統(tǒng)的并發(fā)能力和響應速度,需要的朋友可以參考下
    2023-10-10
  • Springboot Logback日志多文件輸出方式(按日期和大小分割)

    Springboot Logback日志多文件輸出方式(按日期和大小分割)

    這篇文章主要介紹了Springboot Logback日志多文件輸出方式(按日期和大小分割),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • java項目jar包與jdk的版本不兼容的問題解決

    java項目jar包與jdk的版本不兼容的問題解決

    這篇文章主要介紹了java項目jar包與jdk的版本不兼容的問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • Java實現(xiàn)直接插入排序與折半插入排序的示例詳解

    Java實現(xiàn)直接插入排序與折半插入排序的示例詳解

    這篇文章主要為大家詳細介紹了插入排序中兩個常見的排序:直接插入排序與折半插入排序。本文用Java語言實現(xiàn)了這兩個排序算法,感興趣的可以學習一下
    2022-06-06
  • 基于Java代碼操作Redis過程詳解

    基于Java代碼操作Redis過程詳解

    這篇文章主要介紹了基于Java代碼操作Redis過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-10-10
  • java 實現(xiàn)多線程的方法總結(jié)

    java 實現(xiàn)多線程的方法總結(jié)

    這篇文章主要介紹了java 實現(xiàn)多線程的方法總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • RabbitMQ修改默認密碼的操作步驟

    RabbitMQ修改默認密碼的操作步驟

    這篇文章主要給大家介紹了關(guān)于RabbitMQ修改默認密碼的操作步驟,在RabbitMQ中默認用戶guest的密碼是guest,出于安全考慮,最好不要在生產(chǎn)環(huán)境中使用默認用戶和密碼,需要的朋友可以參考下
    2024-11-11
  • Java發(fā)送郵件遇到的常見需求匯總

    Java發(fā)送郵件遇到的常見需求匯總

    這篇文章主要介紹了Java發(fā)送郵件遇到的常見需求匯總的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • JSON,AJAX,Maven入門基礎(chǔ)

    JSON,AJAX,Maven入門基礎(chǔ)

    這篇文章主要介紹了JSON,AJAX和Maven基礎(chǔ),如何使用AJAX讀取Json數(shù)組里面的數(shù)據(jù),感興趣的小伙伴們可以參考一下,希望能夠幫助到你
    2021-07-07
  • Java微信小程序醫(yī)院掛號系統(tǒng)

    Java微信小程序醫(yī)院掛號系統(tǒng)

    這篇文章主要介紹了基于Java微信小程序醫(yī)院掛號系統(tǒng),可以實現(xiàn)遠程處理事務,遠程提交工作和隨時追蹤工作的狀態(tài),文中提供了解決思路和部分實現(xiàn)代碼,需要的朋友可以參考下
    2023-03-03

最新評論

河池市| 黄浦区| 班戈县| 都匀市| 赤峰市| 吕梁市| 米泉市| 赤城县| 阳山县| 灵璧县| 吉林省| 保山市| 黄大仙区| 阜平县| 井研县| 普陀区| 旬邑县| 桓台县| 九龙城区| 新宁县| 崇文区| 贵溪市| 大悟县| 洱源县| 神木县| 邢台市| 呼伦贝尔市| 治多县| 土默特左旗| 罗平县| 嘉义县| 清原| 榆社县| 连南| 孟村| 旬邑县| 镇宁| 绵阳市| 天峨县| 遂川县| 海门市|