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

Java復(fù)制一個對象并且不想復(fù)制其中的空值屬性問題

 更新時間:2023年08月26日 09:45:38   作者:哆啦T夢  
這篇文章主要介紹了Java復(fù)制一個對象并且不想復(fù)制其中的空值屬性問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

Java復(fù)制一個對象并且不想復(fù)制其中的空值屬性

Java復(fù)制一個對象并且不想復(fù)制其中的空值屬性,你可以通過幾種方式來實(shí)現(xiàn)。

Java類庫

1.使用Java中的BeanUtils類。

這個類提供了一個copyProperties()方法,可以用來復(fù)制一個對象的屬性到另一個對象。

默認(rèn)情況下,copyProperties()方法會復(fù)制所有屬性,包括空值屬性。

但是,你可以使用BeanUtils中的BeanUtilsBean類來設(shè)置nullsAreIgnored屬性為true,這樣就可以忽略掉源對象中的空值屬性。

示例代碼如下:

BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
beanUtilsBean.getConvertUtils().register(false, true, 0);
beanUtilsBean.copyProperties(destObject, srcObject);

第三方庫

1.Apache Commons Lang庫中的ObjectUtils類。

這個類提供了一些有用的方法來操作對象,包括復(fù)制對象并忽略空值屬性的方法。

示例代碼如下:

ObjectUtils.clone(srcObject, new CloneNullsStrategy());

其中,CloneNullsStrategy類是一個實(shí)現(xiàn)了org.apache.commons.lang3.ObjectUtils.Null的自定義策略,它用于在復(fù)制對象時忽略空值屬性。

2.hutool的BeanUtil類。

示例代碼如下:

 //null,表示無限制,true表示若父類中屬性值為空則忽略,不傳給子類
 private final CopyOptions copyOption = CopyOptions.create(null, true);
 BeanUtil.copyProperties(srcObject, destObject, copyOption);

Java對象復(fù)制的三種方式

在實(shí)際編程過程中,我們常常要遇到這種情況:有一個對象A,在某一時刻A中已經(jīng)包含了一些有效值,此時可能 會需要一個和A完全相同新對象B,并且此后對B任何改動都不會影響到A中的值,也就是說,A與B是兩個獨(dú)立的對象,但B的初始值是由A對象確定的。

例如下面程序展示的情況:

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;  
        stu1.setNumber(54321);  
        System.out.println("學(xué)生1:" + stu1.getNumber());  
        System.out.println("學(xué)生2:" + stu2.getNumber());  
    }  
}

結(jié)果:

學(xué)生1:54321
學(xué)生2:54321

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

原因出在(stu2 = stu1) 這一句。該語句的作用是將stu1的引用賦值給stu2,這樣,stu1和stu2指向內(nèi)存堆中同一個對象。

那么,怎么能干干凈凈清清楚楚地復(fù)制一個對象呢。在 Java語言中,用簡單的賦值語句是不能滿足這種需求的。

要滿足這種需求有很多途徑:

(1)將A對象的值分別通過set方法加入B對象中;

(2)通過重寫java.lang.Object類中的方法clone();

(3)通過org.apache.commons中的工具類BeanUtils和PropertyUtils進(jìn)行對象復(fù)制;

(4)通過序列化實(shí)現(xiàn)對象的復(fù)制。

將 A 對象的值分別通過 set 方法加入 B 對象中

對屬性逐個賦值,本實(shí)例為了演示簡單就設(shè)置了一個屬性:

Student stu1 = new Student();  
stu1.setNumber(12345);  
Student stu2 = new Student();  
stu2.setNumber(stu1.getNumber());

我們發(fā)現(xiàn),屬性少對屬性逐個賦值還挺方便,但是屬性多時,就需要一直get、set了,非常麻煩。

重寫 java.lang.Object 類中的方法 clone()

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

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

淺克隆

一般步驟:

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

2.覆蓋clone()方法,訪問修飾符設(shè)為public。方法中調(diào)用super.clone()方法得到需要的復(fù)制對象(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("學(xué)生1:" + stu1.getNumber());  
        System.out.println("學(xué)生2:" + stu2.getNumber());  
        stu2.setNumber(54321);  
        System.out.println("學(xué)生1:" + stu1.getNumber());  
        System.out.println("學(xué)生2:" + stu2.getNumber());  
    }  
}  

結(jié)果:

學(xué)生1:12345
學(xué)生2:12345
學(xué)生1:12345
學(xué)生2:54321

在淺克隆中,如果原型對象的成員變量是值類型,將復(fù)制一份給克隆對象;如果原型對象的成員變量是引用類型,則將引用對象的地址復(fù)制一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內(nèi)存地址。

簡單來說,在淺克隆中,當(dāng)對象被復(fù)制時只復(fù)制它本身和其中包含的值類型的成員變量,而引用類型的成員對象并沒有復(fù)制。

在Java語言中,通過覆蓋Object類的clone()方法可以實(shí)現(xiàn)淺克隆。

深克隆

package abc;  
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();   //淺復(fù)制  
        }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("學(xué)生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
        System.out.println("學(xué)生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
        addr.setAdd("西湖區(qū)");  
        System.out.println("學(xué)生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
        System.out.println("學(xué)生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
    }  
}

結(jié)果:

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

怎么兩個學(xué)生的地址都改變了?

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

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

package abc;  
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();   //淺復(fù)制  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        stu.addr = (Address)addr.clone();   //深度復(fù)制  
        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("學(xué)生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
        System.out.println("學(xué)生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
        addr.setAdd("西湖區(qū)");  
        System.out.println("學(xué)生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());  
        System.out.println("學(xué)生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());  
    }  
}

結(jié)果:

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

在深克隆中,無論原型對象的成員變量是值類型還是引用類型,都將復(fù)制一份給克隆對象,深克隆將原型對象的所有引用對象也復(fù)制一份給克隆對象。

簡單來說,在深克隆中,除了對象本身被復(fù)制外,對象所包含的所有成員變量也將復(fù)制。

在Java語言中,如果需要實(shí)現(xiàn)深克隆,可以通過覆蓋Object類的clone()方法實(shí)現(xiàn),也可以通過序列化(Serialization)等方式來實(shí)現(xiàn)。(如果引用類型里面還包含很多引用類型,或者內(nèi)層引用類型的類里面又包含引用類型,使用clone方法就會很麻煩。這時我們可以用序列化的方式來實(shí)現(xiàn)對象的深克隆。

工具類BeanUtils和PropertyUtils進(jìn)行對象復(fù)制

Student stu1 = new Student();  
stu1.setNumber(12345);  
Student stu2 = new Student(); 
BeanUtils.copyProperties(stu2,stu1);

這種寫法無論多少種屬性都只需要一行代碼搞定,很方便吧!除BeanUtils外還有一個名為PropertyUtils的工具類,它也提供copyProperties()方法,作用與BeanUtils的同名方法十分相似,主要的區(qū)別在于BeanUtils提供類型轉(zhuǎn)換功能,即發(fā)現(xiàn)兩個JavaBean的同名屬性為不同類型時,在支持的數(shù)據(jù)類型范圍內(nèi)進(jìn)行轉(zhuǎn)換,而PropertyUtils不支持這個功能,但是速度會更快一些。

在實(shí)際開發(fā)中,BeanUtils使用更普遍一點(diǎn),犯錯的風(fēng)險更低一點(diǎn)。

通過序列化實(shí)現(xiàn)對象的復(fù)制

序列化就是將對象寫到流的過程,寫到流中的對象是原有對象的一個拷貝,而原對象仍然存在于內(nèi)存中。

通過序列化實(shí)現(xiàn)的拷貝不僅可以復(fù)制對象本身,而且可以復(fù)制其引用的成員對象,因此通過序列化將對象寫到一個流中,再從流里將其讀出來,可以實(shí)現(xiàn)深克隆。

需要注意的是能夠?qū)崿F(xiàn)序列化的對象其類必須實(shí)現(xiàn)Serializable接口,否則無法實(shí)現(xiàn)序列化操作。

總結(jié)

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • idea perttier的使用和縮進(jìn)改為4不成功問題及解決

    idea perttier的使用和縮進(jìn)改為4不成功問題及解決

    這篇文章主要介紹了idea perttier的使用和縮進(jìn)改為4不成功問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Java多線程之線程狀態(tài)詳解

    Java多線程之線程狀態(tài)詳解

    這篇文章主要介紹了Java多線程 線程狀態(tài)原理詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2021-09-09
  • Spring中@Conditional注解的詳細(xì)講解及示例

    Spring中@Conditional注解的詳細(xì)講解及示例

    這篇文章主要介紹了Spring中@Conditional注解的詳細(xì)講解及示例,@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件給容器注冊bean,需要的朋友可以參考下
    2023-11-11
  • SpringBoot添加License的多種方式

    SpringBoot添加License的多種方式

    License指的是版權(quán)許可證,當(dāng)我們開發(fā)完系統(tǒng)后,如果不想讓用戶一直白嫖使用,比如說按時間續(xù)費(fèi),License的作用就有了。我們可以給系統(tǒng)指定License的有效期,控制系統(tǒng)的可用時間。
    2021-06-06
  • dom4j讀取XML文件詳解

    dom4j讀取XML文件詳解

    這篇文章主要為大家詳細(xì)介紹了dom4j讀取XML文件的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Java?AQS?原理與?ReentrantLock?實(shí)現(xiàn)方法

    Java?AQS?原理與?ReentrantLock?實(shí)現(xiàn)方法

    AQS 的作用是解決同步器的實(shí)現(xiàn)問題,它將復(fù)雜的同步器實(shí)現(xiàn)分解為簡單的框架方法,開發(fā)者只需要實(shí)現(xiàn)少量特定的方法就能快速構(gòu)建出可靠的同步器,這篇文章主要介紹Java AQS原理與ReentrantLock實(shí)現(xiàn),需要的朋友可以參考下
    2025-03-03
  • mybatis TypeHandler注入spring的依賴方式

    mybatis TypeHandler注入spring的依賴方式

    這篇文章主要介紹了mybatis TypeHandler注入spring的依賴方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • SpringBoot配置Email發(fā)送功能實(shí)例

    SpringBoot配置Email發(fā)送功能實(shí)例

    本篇文章主要介紹了SpringBoot配置Email發(fā)送功能實(shí)例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Java+MySQL 圖書管理系統(tǒng)

    Java+MySQL 圖書管理系統(tǒng)

    這篇文章是BUFFER.pwn同學(xué)分享的基于Java與MySQL的圖書管理系統(tǒng),需要的朋友可以參考一下
    2021-04-04
  • Java工廠模式的深入了解

    Java工廠模式的深入了解

    這篇文章主要為大家介紹了Java工廠模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01

最新評論