hession2序列化

1 引入Hessian依賴

<!--hessian-->
    <dependency>
      <groupId>com.caucho</groupId>
      <artifactId>hessian</artifactId>
      <version>4.0.38</version>
    </dependency>

2 編寫Hessian序列化,反序列化方法,定義實體類 示例

public class HessianSerializerUtil {

    public static <T> byte[] serialize(T obj) {
        byte[] bytes = null;
        // 1、創建字節輸出流
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        // 2、對字節數組流進行再次封裝

        // step 1. 定義外部序列化工廠
        //ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();
        //extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());
        //extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());
        // step 2. 序列化工廠
        //SerializerFactory serializerFactory = new SerializerFactory();
        //serializerFactory.addFactory(extSerializerFactory);

        HessianOutput hessianOutput = new HessianOutput(bos);
        //hessianOutput.setSerializerFactory(serializerFactory);

        try {
            // 注意,obj 必須實現Serializable接口
            hessianOutput.writeObject(obj);
            bytes = bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bytes;
    }

    public static <T> T deserialize(byte[] data) {
        if (data == null) {
            return null;
        }
        // 1、將字節數組轉換成字節輸入流
        ByteArrayInputStream bis = new ByteArrayInputStream(data);

        // step 1. 定義外部序列化工廠
        //ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();
        //extSerializerFactory.addSerializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisSerializer());
        //extSerializerFactory.addDeserializer(java.time.OffsetDateTime.class, new OffsetDateTimeRedisDeserializer());
        // step 2. 序列化工廠
        //SerializerFactory serializerFactory = new SerializerFactory();
        //serializerFactory.addFactory(extSerializerFactory);
        HessianInput hessianInput = new HessianInput(bis);
        //hessianInput.setSerializerFactory(serializerFactory);
        Object object = null;

        try {
            object = hessianInput.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return (T) object;
    }
}
package cn.micai.base.io;
 
import java.io.Serializable;
 
/**
 * 描述:
 * <p>
 *
 *     transient使用小結
 *     1.一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化後無法獲得訪問。
 *     2.transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量如果是用戶自定義類變量,則該類需要實現Serializable接口。
 *     3.被transient關鍵字修飾的變量不再能被序列化,一個靜態變量不管是否被transient修飾,均不能被序列化。
 *
 * @author: 趙新國
 * @date: 2018/6/7 12:10
 */
public class Employee implements Serializable {
 
    private static final long serialVersionUID = 1L;
    private int employeeId;
    private String employeeName;
    /**
     * 使用transient關鍵字,表示該字段不序列化
     */
    private transient String department;
 
    public int getEmployeeId() {
        return employeeId;
    }
    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }
    public String getEmployeeName() {
        return employeeName;
    }
    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }
    public String getDepartment() {
        return department;
    }
    public void setDepartment(String department) {
        this.department = department;
    }
 
    @Override
    public String toString() {
        return "Employee{" +
                "employeeId=" + employeeId +
                ", employeeName='" + employeeName + '\'' +
                ", department='" + department + '\'' +
                '}';
    }
}

 

 

hession 序列化的特點

  •  1.一旦變量被transient修飾,變量將不再是對象持久化的一部分,該變量內容在序列化後無法獲得訪問。
  •  2.transient關鍵字只能修飾變量,而不能修飾方法和類。被序列化的類需要實現Serializable接口。
  •  3.一個靜態變量不管是否被transient修飾,均不能被序列化
  •  4 final類型變量 不管是否被transient修飾,均可以被序列化。
  • 5 Student類集成Teacher類,Teacher類中有跟Student類型相同且屬性名相同的字段name,接下來看代碼:
public class Person implements Serializable {
    private static final long serialVersionUID = 2l;
    private  int gender;

    public int getGender() {
        return gender;
    }

    public void setGender(int gender) {
        this.gender = gender;
    }

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

public class Em extends Person {

    private int gender;

    public Em() {
    }

    @Override
    public int getGender() {
        return gender;
    }

    @Override
    public void setGender(int gender) {
        this.gender = gender;
        //super.setGender(gender);
    }

    @Override
    public String toString() {
        return "Em{" +
                "gender=" + gender +
                '}';
    }
}



測試類:
   public class Set {

    public static void main(String[] args) throws Exception{

        Em person=new Em();
        person.setGender(1);


        FileOutputStream fos = new FileOutputStream("tempdata.ser");
        Hessian2Output output = new Hessian2Output(fos);
        output.writeObject(person);
        output.close();


        FileInputStream fis = new FileInputStream("tempdata.ser");
        Hessian2Input input = new Hessian2Input(fis);


        Em p = (Em) input.readObject();
        System.out.println(p);





    }
}

輸出結果爲:
Em{gender=0}

理論上輸出的結果應該爲“gender=1”,但現在爲gender=0,原因如下:

  1. hessian序列化的時候會取出對象的所有自定義屬性,相同類型的屬性是子類在前父類在後的順序;
  2. hessian在反序列化的時候,是將對象所有屬性取出來,存放在一個map中 key = 屬性名 value是反序列類,相同名字的會以子類爲準進行反序列化;
  3. 相同名字的屬性 在反序列化的是時候,由於子類在父類前面,子類的屬性總是會被父類的覆蓋,由於java多態屬性,在上述例子中父類 student.name = null。

得出結論,兩種解決辦法

1 使用hessian序列化時,一定要注意子類和父類不能有同名字段

2 在給子類賦值的時候,也給父類賦值。

 @Override
    public void setGender(int gender) {
        this.gender = gender;
        //super.setGender(gender);
    }

 

  • 反序列化的時候  類裏多了字段,會初始化成默認值,少了值,會自動忽略。
  • 不須使用serialVersionUID  作爲版本標識。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章