java深度複製

weixin_34148456發表於2017-05-06

參考:Java 實現深度複製

什麼是深度複製?在Java裡面,在建立一個物件,我們通常會有一個引用指向該物件,當我們通過引用變數改變物件的值(屬性)時,引用是不變的,變的是記憶體裡面的那塊記憶體,即引用所指向的物件。一般情況下,我們將該引用賦給另一個引用變數或者作為引數傳遞時,傳遞的也只是引用,即將引用指向“複製”了一份給另一個引用變數,隨後該引用變數也指向同一個物件,記憶體裡面並沒有建立一個新的物件。在某些情況下,我們需要“真正複製”物件,建立一份已知物件的copy,而不僅僅“複製”引用,用作備份也好,其他操作也好。
那麼,該如何實現?
先說下思路:首先將物件序列化到流裡,然後再反序列化,從流裡讀取出來即可。

java序列化和反序列化

  • 概念
      序列化:把Java物件轉換為位元組序列的過程。
      反序列化:把位元組序列恢復為Java物件的過程。
  • 用途
      物件的序列化主要有兩種用途:
      1) 把物件的位元組序列永久地儲存到硬碟上,通常存放在一個檔案中;
      2) 在網路上傳送物件的位元組序列。
  • 物件序列化

java.io.ObjectOutputStream代表物件輸出流,它的writeObject(Object obj)方法可對引數指定的obj物件進行序列化,把得到的位元組序列寫到一個目標輸出流中。只有實現了Serializable和Externalizable介面的類的物件才能被序列化。
  java.io.ObjectInputStream代表物件輸入流,它的readObject()方法從一個源輸入流中讀取位元組序列,再把它們反序列化為一個物件,並將其返回。

java物件序列化條件

  • 實現Serializable介面
  • declare a static final serialVersionUID field of type long

常用序列化方法

  1. 序列化
// 位元組陣列輸出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 物件輸出流
ObjectOutputStream oos = new ObjectOutputStream(baos);
// 序列化
oos.writeObject(new Integer(100));    //序列化整數100

2.反序列化

byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();

例項:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
*
* @author Administrator
* 深度複製
*/
public class App2 {
public static void main(String[] args) throws Exception {
/******************** 寫入(序列) **********************/
// 位元組陣列輸出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 物件輸出流
ObjectOutputStream oos = new ObjectOutputStream(baos);
// 序列化
oos.writeObject(new Integer(100));
oos.writeObject("Hello World");
oos.writeObject(new Cat("xiaohu",18));
oos.close();
baos.close();
/******************** 讀取(反序列) **********************/
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();
System.out.println(o);
o = ois.readObject();
System.out.println(o);
Cat cat = (Cat)ois.readObject();
System.out.println("name: "+cat.getName()+" age: "+cat.getAge());
ois.close();
bais.close();
}
}

Cat類:

import java.io.Serializable;
/**
 * javaBean
 */
public class Cat implements Serializable {
    private static final long serialVersionUID = 1861516170581376793L;
    private String name;
    private int age;
    private String color ;
    private int xx ;
    //臨時的
    private transient Person owner ;
    
    private Dog neibor ;
    
    public Dog getNeibor() {
        return neibor;
    }
    public void setNeibor(Dog neibor) {
        this.neibor = neibor;
    }
    public Person getOwner() {
        return owner;
    }
    public void setOwner(Person owner) {
        this.owner = owner;
    }
    public int getXx() {
        return xx;
    }
    public void setXx(int xx) {
        this.xx = xx;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public Cat() {
        System.out.println("()");
    }
    public Cat(String name, int age) {
        super();
        System.out.println("(1)");
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

Person類


import java.io.Serializable;

public class Person implements Serializable{
    
    private static final long serialVersionUID = -3860831553852022224L;
    
    private String name ;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

Dog類:

package com.it18zhang.test;

import java.io.Serializable;

public class Dog implements Serializable{
    
    private static final long serialVersionUID = 264736816365982588L;
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

總結:

  • java深度複製非常實用,特別是在分散式應用當中,比如Hadoop,Spark等當中,通常採用主流的序列化框架如protobuf,avro,thrift等將資料物件進行序列化成位元組陣列,然後通過rpc(遠端過程呼叫)的機制通過通訊協議進行傳輸,從而實現分散式應用之間的通訊。在節省網路頻寬和磁碟io的基礎上更加提高了網路傳輸的效率和安全性。
  • 完成RPC 需要兩個協議: 物件序列化協議 和 呼叫控制協議

相關文章