什么是Java拷貝

什么是Java拷貝

創(chuàng)建一個(gè)和已知對(duì)象一摸一樣的對(duì)象。

創(chuàng)建對(duì)象5中方法

  1. new 關(guān)鍵字。
  2. Class 類的 newInstance() 方法。
  3. Constructor 類的 newInstance() 方法。
  4. Object 類 clone() 方法。
  5. 反序列化。
// 克隆必須實(shí)現(xiàn) Cloneable 接口
// 序列化必須實(shí)現(xiàn) Serializable 接口
public class User implements Cloneable, Serializable {
    private String username;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                '}';
    }

    @Override
    public User clone() {
        try {
            return (User) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // new 關(guān)鍵字
        User user = new User();
        user.setUsername("new 關(guān)鍵字");
        System.out.println(user);
        System.out.println(user.hashCode());

        // Class 類的 newInstance() 方法
        Class<?> aClass = Class.forName("cn.eric.register.client.test.User");
        User user1 = (User) aClass.newInstance();
        user1.setUsername("Class 類的 newInstance() 方法");
        System.out.println(user1);
        System.out.println(user1.hashCode());

        // Constructor 類的 newInstance() 方法
        User user2 = User.class.getDeclaredConstructor().newInstance();
        user2.setUsername("Constructor 類的 newInstance() 方法");
        System.out.println(user2);
        System.out.println(user2.hashCode());

        // Object 類 clone() 方法
        User user3 = user.clone();
        System.out.println(user3);
        System.out.println(user3.hashCode());

        // 輸出流,序列化寫入文件
        String s = "C:\\Users\\Administrator\\Desktop\\a.txt";
        FileOutputStream fileOutputStream = new FileOutputStream(s);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(user);
        objectOutputStream.flush();
        
        // 輸入流,讀取文件,反序列化為對(duì)象
        FileInputStream fileInputStream = new FileInputStream(s);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        User user4 = (User)objectInputStream.readObject();

        System.out.println(user4);
        System.out.println(user4.hashCode());
    }

基本類型和引用類型

基本類型也稱為值類型

char,boolean,byte,short,int,long,float,double

引用類型包括: 類,接口,數(shù)組,枚舉等

值類型于引用類型.png

淺拷貝

// lombok
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public class User implements Cloneable, Serializable {
    private String username;
    private Integer age;
    private Cat cat;

    @Override
    public User clone() {
        try {
            return (User) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@ToString
public class Cat {
    private String catName;
}
public static void shallowCopy()   {
    User user = new User();
    Cat cat = new Cat();
    cat.setCatName("小白");
    user.setUsername("張三");
    user.setAge(11);
    user.setCat(cat);

    User user1 = user.clone();

    user1.setUsername("李四");
    user1.setAge(12);
    user1.getCat().setCatName("小黑");

    System.out.println(user);
    System.out.println(user1);
    // 輸出結(jié)果
    // User(username=張三, age=11, cat=Cat(catName=小黑))
    // User(username=李四, age=12, cat=Cat(catName=小黑))
}

所以以上代碼 cat 修改后 原 對(duì)象也跟著修改了。

淺拷貝.png

String, Integer 也是引用類型為啥沒(méi)有復(fù)制引用而是復(fù)制了值呢?

其實(shí)不是的 String 和 Integer 其實(shí)也是復(fù)制了引用. 只是表象讓我們看起來(lái)像是 復(fù)制的 值.

public static void shallowCopy()   {
    User user = new User();
    Cat cat = new Cat();
    cat.setCatName("小白");
    user.setUsername("張三");
    user.setAge(11);
    user.setCat(cat);

    User user1 = user.clone();

    //        user1.setUsername("李四");
    //        user1.setAge(12);
    //        user1.getCat().setCatName("小黑");

    System.out.println(user);
    System.out.println(user1);


    System.out.println("user.hash" + user.hashCode());
    System.out.println("user1.hash" + user1.hashCode());
    System.out.println("user.username.hash" + user.getUsername().hashCode());
    System.out.println("user1.username.hash" + user1.getUsername().hashCode());
    System.out.println(user.getUsername() == user1.getUsername());

    //        輸出內(nèi)容
    //        User(username=張三, age=11, cat=Cat(catName=小白))
    //        User(username=張三, age=11, cat=Cat(catName=小白))
    //        user.hash46723090
    //        user1.hash46723090
    //        user.username.hash774889
    //        user1.username.hash774889
    //        true
}

我們發(fā)現(xiàn)如果我們注釋掉修改 username 的代碼 發(fā)現(xiàn) username 的 hash 值是一摸一樣的。而且 == 對(duì)比也是相等的.

說(shuō)明 字符串 其實(shí)確實(shí)是復(fù)制的引用。 看起來(lái)像是值引用的原因就是 String 類是 final 修飾的。

String 是不可變的。修改就是重新創(chuàng)建一個(gè)字符串并將棧內(nèi)的指向改為新創(chuàng)建的堆。

Integer 同理。

String不可變.png

深拷貝

深拷貝就是所有字段都拷貝一份.即使是引用類型對(duì)象也一樣.

實(shí)現(xiàn)方法就是所有的引用類型對(duì)象也實(shí)現(xiàn)一下 Cloneable接口. 并重寫 clone方法.

但是此時(shí)有個(gè)問(wèn)題.例如 上方代碼 User 類里不僅僅有 Cat 還有 Dog 還有 Duck 等等.... Cat 里面還有 Snacks 等等 一層一層一個(gè)一個(gè)又一個(gè)的對(duì)象. 代碼量就多了.

使用反序列化實(shí)現(xiàn) 深拷貝是個(gè)不錯(cuò)的辦法. 注意: 所有的類都要實(shí)現(xiàn)Serializable接口序列化才行.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java的淺拷貝與深拷貝 一、概念 淺拷貝淺拷貝僅僅復(fù)制所考慮的對(duì)象(包括對(duì)象中的基本變量),而不復(fù)制它所引用的對(duì)...
    JackKuang閱讀 565評(píng)論 0 0
  • 一、對(duì)象拷貝 我們使用 = 的時(shí)候,其實(shí)是引用的拷貝. 多個(gè)引用指向的其實(shí)是同一個(gè)對(duì)象.上面的例子中 Array...
    ukyoo閱讀 1,598評(píng)論 0 5
  • 創(chuàng)建Java對(duì)象的方式包括new、反射、反序列化、拷貝,那么什么是拷貝呢?淺拷貝和深拷貝又有什么區(qū)別呢? 什么是拷...
    分布式與微服務(wù)閱讀 802評(píng)論 0 1
  • 前言 本文快速回顧了Java中最基礎(chǔ)的知識(shí)點(diǎn),用作面試復(fù)習(xí),事半功倍。 參考 微信文章:精華:Java 開發(fā)崗面試...
    蠻三刀醬閱讀 943評(píng)論 0 0
  • 目錄介紹 01.對(duì)象拷貝有哪些 02.理解淺拷貝2.1 什么是淺拷貝2.2 實(shí)現(xiàn)淺拷貝案例 03.理解深拷貝3.1...
    楊充211閱讀 898評(píng)論 0 1

友情鏈接更多精彩內(nèi)容