天天看點

序列化,transient關鍵字使用紀要

背景: 抽空整理一下.特此紀要!

問題: 
	1. transient是什麼?
	2. transient關鍵字能做什麼?
	3. transient底層實作原理是什麼?

解答:
	1. transient是什麼?
		transient是java中的一個關鍵字.

	2. transient關鍵字能做什麼?
		transient關鍵字用來修飾不需要序列化的對象屬性,當對象的某個屬性被transient關鍵字修飾後,序列化這個對象的時候,這個屬性就不會被序列化.
 		
 	3. transient底層的實作原理是什麼?
 		java的serialization提供了一種存儲對象狀态的機制.将對象的狀态資料存儲到磁盤,等需要的時候将其取出來.而某些業務場景對于一些特殊的屬性不希望在網絡上傳輸,
 	此時transient關鍵字就起到了決定性的作用,他可以将被其修飾的對象屬性的生命周期限定在記憶體中,也就是說最終不會被寫入到記憶體.


下面有一則用例,可以快速了解關于序列化的相關内容:
           
package cn.api.serialize;

import java.io.*;

/**
 * Serialize Api 序列化API
 *  Java序列化是指将java對象轉化為位元組序列的過程. 而Java反序列化是指将位元組序列恢複為java對象的過程.進而達到網絡傳輸,本地存儲的效果.
 *
 *  transient關鍵字的應用
 *  序列化的兩種方式:
 *      1. Serializable
 *      2. Externalizable
 *  Serializable和Externalizable的差別?
 *      Externalizable實作自Serializable.
 *      使用Externalizable序列化需要實作writeExternal()和readExternal().
 *          說明: 使用Externalizable實作序列化需要手動提供序列化對象的無參構造器.
 *      使用Externalizable序列化不需要産生序列化ID(serialVersionUID),而通過Serializable方式實作序列化時需要初始化序列化ID(serialVersionUID).
 *      相對于Serializable,使用Externalizable實作序列化其占用的記憶體要比Serializable要小,速度也要比Serializable要快.
 *      Serializable使用兩種方式實作序列化[
 *          1. 對非transient以及非static的屬性進行序列化.
 *          2. 實作writeExternal()和readExternal()進行指定屬性的序列化.
 *      ] 說明: Serializable不需要提供序列化對象無參構造器的原因是,Serializable使用反射機制完成内容回複.是以沒有一定要添加序列化對象的無參構造器的限制.
 * 項目中為了快速響應一般都是用Serializable來完成資料對象的序列化.有些類可以使用Externalizable接口,如: [
 *  完全控制序列的流程和邏輯.
 *  需要大量的使用序列化和反序列化操作,此時你比較關心資源和性能.(此時也可以通過第三方序列化反序列化工具來實作. 如:protobuf(Google),thrift(Facebook),AvroGeneric...)
 * ]
 */
public class SerializeApi {

    /**
     * Obj User
     */
    static class User implements Serializable{

        private final long serialVersionID = -628948656629515L;

        private String name;

        private transient int age;

        public long getSerialVersionID() {
            return serialVersionID;
        }

        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;
        }
    }

    /**
     * Obj SerializableApiTest
     * @Explain transient修飾的非靜态屬性不會被序列化(靜态屬性在公共的方法區,是以靜态變量用不用transient修飾都不會被序列化)
     */
    static class SerializableApiTest {

        private static void serializeUser() throws Exception {
            User user = new User();
            user.setName("Mir's Liu");
            user.setAge(10003);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D://template"));
            objectOutputStream.writeObject(user);
            objectOutputStream.close();
            System.out.println("transient attribute is age: " + user.getAge());
        }

        private static void deSerializeUser() throws Exception {
            File file = new File("D://template");
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            User user = (User)objectInputStream.readObject();
            System.out.println("revert transient attribute is age: " + user.getAge());
        }

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

            serializeUser();

            deSerializeUser();

        }
    }

    /**
     * Obj User1
     * @Exceplain 使用Externalizable實作序列化後,需要實作writeExternal()和readExternal()對不需要序列化的屬性要手動設定(設定後即使transient修飾也是一樣).
     */
    static class User1 implements Externalizable {

        /** 實作了指定參數序列化後,加不加transient都會被序列化 */
        private transient String name;

        private Integer age;

        /** 虛歲(Virtual year) */
        private Integer virtualYear;

        public User1() {}

        public String getName() {
            return name;
        }

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

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public Integer getVirtualYear() {
            return virtualYear;
        }

        public void setVirtualYear(Integer virtualYear) {
            this.virtualYear = virtualYear;
        }

        /**
         * 手動實作指定參數的序列化
         * @param out
         * @throws IOException
         */
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeObject(name);
            out.writeObject(age);
            out.writeObject(virtualYear);
        }

        /**
         * 手動實作指定參數的反序列化
         * @param in
         * @throws IOException
         * @throws ClassNotFoundException
         */
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            name = (String) in.readObject();
            age = (Integer) in.readObject();
            virtualYear = (Integer) in.readObject();
        }

        @Override
        public String toString() {
            return "User1{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", virtualYear=" + virtualYear +
                    '}';
        }
    }

    /**
     * Obj ExternalizeAdiTest
     */
    static class ExternalizeAdiTest {

        private static void externalizeUser() throws Exception {
            User1 user = new User1();
            user.setName("Mir's Li");
            user.setAge(22);
            user.setVirtualYear(23);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D://template"));
            objectOutputStream.writeObject(user);
            objectOutputStream.close();
            System.out.println("transient attribute is name: " + user.toString());
        }

        private static void deExternalizeUser() throws Exception {
            File file = new File("D://template");
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            User1 user = (User1)objectInputStream.readObject();
            System.out.println("revert transient attribute is name: " + user.toString());
        }

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

            externalizeUser();

            deExternalizeUser();

        }
    }

    /**
     * Obj User2
     */
    static class User2 implements Serializable {

        private static transient String name;

        private int age;

        public static String getName() {
            return name;
        }

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

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User2{" +
                    "age=" + age +
                    '}';
        }
    }

    static class StaticSerializableApiTest {

        private static void serializableUser2(int age) throws Exception {
            User2 user2 = new User2();
            user2.setName("Mir's Li");
            user2.setAge(age);
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D://template"));
            objectOutputStream.writeObject(user2);
            objectOutputStream.close();
            System.out.println("User2: (after) " + user2.toString());
        }

        private static void deSerializableUser2() throws Exception {
            File file = new File("D://template");
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
            User2 user2 = (User2)objectInputStream.readObject();
            System.out.println("User2: (end) " + user2.toString());
        }

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

            serializableUser2(12);

            deSerializableUser2();

            serializableUser2(122);

            deSerializableUser2();
        }
    }
}