transient关键字解析_不序列化

transient关键字的定义

定义:transient只能用来修饰成员变量(field),被transient修饰的成员变量不参与序列化过程。
简析:Java中的对象如果想要在网络上传输或者存储在磁盘时,就必须要序列化。Java中序列化的本质是Java对象转换为字节序列。但是在序列化的过程中,可以允许被序列对象中的某个成员变量不参与序列化,即该对象完成序列化之后,被transient修饰的成员变量会在字节序列中消失。

小明的昵称希望被人看到,但是真名不希望被人看到。

package com.ygl.demo3;

import java.io.Serializable;

public class XiaoMing implements Serializable {
    private static final long serialVersionUID = 1271321732347324L;
    private String nickName;
    private transient String realName;

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public XiaoMing(String nickName, String realName) {
        this.nickName = nickName;
        this.realName = realName;
    }

    @Override
    public String toString() {
        return "XiaoMing{" +
                "nickName='" + nickName + '\'' +
                ", realName='" + realName + '\'' +
                '}';
    }
}

package com.ygl.demo3;

import java.io.*;

public class TestXiaoMing {
    public static void main(String[] args) throws IOException {
        XiaoMing xiaoMing = new XiaoMing("ming", "鸿铭");
        System.out.println("序列化前:"+xiaoMing.toString());
        ObjectOutputStream oo = null;
        ObjectInputStream oi = null;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(new File("./xiaoming.txt")));
            oo.writeObject(xiaoMing);
            oi = new ObjectInputStream(new FileInputStream(new File("./xiaoming.txt")));
            XiaoMing x = (XiaoMing) oi.readObject();
            System.out.println("序列化后:"+x.toString());
        }catch (IOException | ClassNotFoundException e){
            System.out.println(e.getStackTrace());
        }finally {
            oi.close();
            oo.close();
        }
    }
}

结果

序列化前:XiaoMing{nickName='ming', realName='鸿铭'}
序列化后:XiaoMing{nickName='ming', realName='null'}

静态成员变量不加transient关键字也不能被序列化

在Java中,静态成员变量是不能被序列化的,不管有没有transient关键字。

The readObject method is responsible for reading from the stream and 
restoring the classes fields. It may call in.defaultReadObject to
invoke the default mechanism for restoring the object's non-static 
and non-transient fields. The defaultReadObject method uses 
information in the stream to assign the fields of the object saved in
the stream with the correspondingly named fields in the current 
object. This handles the case when the class has evolved to add new
fields. The method does not need to concern itself with the state 
belonging to its superclasses or subclasses. State is saved by 
writing the individual fields to the ObjectOutputStream using the 
writeObject method or by using the methods for primitive data types
supported by DataOutput.
package com.ygl.demo3;

import java.io.Serializable;

public class XiaoMing implements Serializable {
    private static final long serialVersionUID = 1271321732347324L;
    private String nickName;
    private transient String realName;
    private static String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        XiaoMing.address = address;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public XiaoMing(String nickName, String realName) {
        this.nickName = nickName;
        this.realName = realName;
    }

    @Override
    public String toString() {
        return "XiaoMing{" +
                "nickName='" + nickName + '\'' +
                ", realName='" + realName + '\'' +
                '}';
    }

}

package com.ygl.demo3;

import java.io.*;

public class TestXiaoMing {
    public static void main(String[] args) throws IOException {
        XiaoMing xiaoMing = new XiaoMing("ming", "鸿铭");
        xiaoMing.setAddress("西府大街22号");
        System.out.println("序列化前:"+xiaoMing.toString()+xiaoMing.getAddress());
        ObjectOutputStream oo = null;
        ObjectInputStream oi = null;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(new File("./xiaoming.txt")));
            oo.writeObject(xiaoMing);
            oi = new ObjectInputStream(new FileInputStream(new File("./xiaoming.txt")));
            XiaoMing x = (XiaoMing) oi.readObject();
            System.out.println("序列化后:"+x.toString()+x.getAddress());
        }catch (IOException | ClassNotFoundException e){
            System.out.println(e.getStackTrace());
        }finally {
            oi.close();
            oo.close();
        }
    }
}

结果发现加了static关键字的address成员变量可以反序列化,这是为什么呢?
因为测试都在同一个机器(而且是同一个进程),因为这个jvm已经把address加载进来了,所以获取的是加载好的address,如果是传到另一台机器或者关掉程序重新写个程序读入xiaoming.txt,此时因为别的机器或新的进程是重新加载i的,所以address信息就是初始时的信息null

序列化前:XiaoMing{nickName='ming', realName='鸿铭'}西府大街22号
序列化后:XiaoMing{nickName='ming', realName='null'}西府大街22
package com.ygl.demo3;

import java.io.*;

public class TestXiaoMing {
    public static void main(String[] args) throws IOException {
        XiaoMing xiaoMing = new XiaoMing("ming", "鸿铭");
        xiaoMing.setAddress("西府大街22号");
        System.out.println("序列化前:"+xiaoMing.toString()+xiaoMing.getAddress());
        ObjectOutputStream oo = null;
        //ObjectInputStream oi = null;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(new File("./xiaoming.txt")));
            oo.writeObject(xiaoMing);
//            oi = new ObjectInputStream(new FileInputStream(new File("./xiaoming.txt")));
//            XiaoMing x = (XiaoMing) oi.readObject();
//            System.out.println("序列化后:"+x.toString()+x.getAddress());
        }catch (IOException e){
            System.out.println(e.getStackTrace());
        }finally {
            //oi.close();
            oo.close();
        }
    }
}

package com.ygl.demo3;

import java.io.*;

public class TestXiaoMing2 {
    public static void main(String[] args) throws IOException {
        ObjectInputStream oi = null;
        try {
            oi = new ObjectInputStream(new FileInputStream(new File("./xiaoming.txt")));
            XiaoMing x = (XiaoMing) oi.readObject();
            System.out.println("序列化后:"+x.toString()+x.getAddress());
        }catch (IOException | ClassNotFoundException e){
            System.out.println(e.getStackTrace());
        }finally {
            oi.close();
        }
    }
}

序列化后:XiaoMing{nickName='ming', realName='null'}null

使用Externalizable自定义序列化

Externalizable这个接口也是实现序列化的,但是和Serializable有不同。首先,Externalizable是继承Serializable的,其次Externalizable是需要程序员自己指定成员变量实现序列化的。

也就是说,使用Externalizable接口,程序员需要实现writeExternal以及readExternal这两个方法,来自己实现序列化和反序列化。实现的过程中,需要自己指定需要序列化的成员变量,此时,static和transient关键词都是不生效的,因为你重写了序列化中的方法。

package com.ygl.demo3;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class XiaoMing2 implements Externalizable {
    private static final long serialVersionUID = 1271321732347324L;
    private String nickName;
    private transient String realName;
    private static String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        XiaoMing2.address = address;
    }

    public String getNickName() {
        return nickName;
    }

    public void setNickName(String nickName) {
        this.nickName = nickName;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public XiaoMing2(String nickName, String realName) {
        this.nickName = nickName;
        this.realName = realName;
    }

    public XiaoMing2() {
    }

    @Override
    public String toString() {
        return "XiaoMing{" +
                "nickName='" + nickName + '\'' +
                ", realName='" + realName + '\'' +
                '}';
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(realName);
        out.writeUTF(nickName);
        out.writeUTF(XiaoMing2.address);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        realName = in.readUTF();
        nickName = in.readUTF();
        XiaoMing2.address = in.readUTF();
    }
}

package com.ygl.demo3;

import java.io.*;

public class TestXiaoMing {
    public static void main(String[] args) throws IOException {
        XiaoMing2 xiaoMing = new XiaoMing2("ming", "鸿铭");
        xiaoMing.setAddress("西府大街22号");
        System.out.println("序列化前:"+xiaoMing.toString()+xiaoMing.getAddress());
        ObjectOutputStream oo = null;
        //ObjectInputStream oi = null;
        try {
            oo = new ObjectOutputStream(new FileOutputStream(new File("./xiaoming.txt")));
            oo.writeObject(xiaoMing);
//            oi = new ObjectInputStream(new FileInputStream(new File("./xiaoming.txt")));
//            XiaoMing x = (XiaoMing) oi.readObject();
//            System.out.println("序列化后:"+x.toString()+x.getAddress());
        }catch (IOException e){
            System.out.println(e.getStackTrace());
        }finally {
            //oi.close();
            oo.close();
        }
    }
}

package com.ygl.demo3;

import java.io.*;

public class TestXiaoMing2 {
    public static void main(String[] args) throws IOException {
        ObjectInputStream oi = null;
        try {
            oi = new ObjectInputStream(new FileInputStream(new File("./xiaoming.txt")));
            XiaoMing2 x = (XiaoMing2)oi.readObject();
            System.out.println("序列化后:"+x.toString()+x.getAddress());
        }catch (IOException | ClassNotFoundException e){
            System.out.println(e.getStackTrace());
        }finally {
            oi.close();
        }
    }
}

序列化后:XiaoMing{nickName='ming', realName='鸿铭'}西府大街22

你可能感兴趣的:(笔记,java)