定义: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'}
在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这个接口也是实现序列化的,但是和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号