transient关键字与序列化、反序列化
transient,中文翻译是短暂的,和对象序列化、反序列化有关。
一个类只要实现了Serializable接口,则该类实例就可以序列化,具体来说实例的每个非静态成员变量都会序列化。注意是非静态成员变量,静态成员变量不会序列化。但是假如某些字段涉及敏感信息,不能序列化存储到文件中或者经网络传输,则就应该用transient修饰。用transient修饰的变量在对象序列化时默认不会序列化,同时反序列化得到的对象中该变量值会是对应类型的默认值。
代码示例:
Address类:
public class Address implements Serializable {
private String nation;
private String city;
private String buildingNo;
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getBuildingNo() {
return buildingNo;
}
public void setBuildingNo(String buildingNo) {
this.buildingNo = buildingNo;
}
public Address() {
}
public Address(String nation, String city, String buildingNo) {
this.nation = nation;
this.city = city;
this.buildingNo = buildingNo;
}
@Override
public String toString() {
return "Address{" +
"nation='" + nation + '\'' +
", city='" + city + '\'' +
", buildingNo='" + buildingNo + '\'' +
'}';
}
}
Person类:
public class Person implements Serializable {
private String name;
private Integer age;
private Address address;
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 Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Person(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
测试类Test:
public class Test {
public static void main(String[] args) {
String path = "d:/s.txt";
try (OutputStream output = new FileOutputStream(path);
ObjectOutputStream oos = new ObjectOutputStream(output);
InputStream input = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(input)
) {
oos.writeObject(new Person("zhangsan", 18, new Address("China", "Shenzhen", "FuTian")));
Person person = (Person) ois.readObject();
System.out.println(person);
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意,上面说的是用transient修饰的变量在对象序列化时默认不会序列化,同时反序列化得到的对象中该变量值会是对应类型的默认值。注意,是默认,不是一定。因为是有办法让transient修饰的变量也参与序列化的。只需在类中加入两个方法即可:
void writeObject(ObjectOutputStream oos) throws IOException;
void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException;
其中第一个是序列化方法,可以指定序列化的成员变量,第二个是反序列化方法,可以指定反序列化的成员变量。可以在这两个方法中显式指定被transient修饰的变量,这样该变量同样可以参与序列化和反序列化。
代码示例:
其他类代码不变,Person类:
public class Person implements Serializable {
private String name;
private Integer age;
private transient Address address;
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 Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Person(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeObject(address);
System.out.println("person serialized");
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
address = (Address) ois.readObject();
System.out.println("person deserialized");
}
}
上面代码中,标红的oos.defaultWriteObject(); 和 ois.defaultReadObject(); 是调用默认的序列化方法和反序列化方法去操作没有transient修饰的非静态成员变量(default方法能且仅能操作non-static、non-transient变量),之后用oos.writeObject(address); 和 address = (Address) ois.readObject(); 来显式指定address变量。这样,执行完Test类的main方法之后,同样可以打印出adderss信息,即使address用transient修饰了。
Serializable接口还有个Externalizable子接口。该接口有2个方法:
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
如果自定义类实现了Externalizable接口,则transient在该类中不起任何作用,属性能不能序列化和有没有transient修饰没有半毛钱关系。如果想序列化该类实例的某个属性,必须在writeExternal()方法中显式write,如果想反序列化时能够获取到属性值,必须在readExternal()显式read,且各属性write和read的顺序必须一样。如果writeExternal()方法和readExternal()方法中没有具体实现,则任何属性都不会序列化。
代码示例:
其他类不变,Person类:
public class Person implements Externalizable {
private String name;
private Integer age;
private transient Address address;
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 Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Person() {
}
public Person(String name, Integer age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(age);
out.writeObject(address);
System.out.println("person serialized");
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name = (String) in.readObject();
age = (Integer) in.readObject();
address = (Address) in.readObject();
System.out.println("person deserialized");
}
}
需要指出的是,假如想要通过反序列化来得到Externalizable实例,则Externalizable接口实现类必须要有无参构造器,否则会报java.io.InvalidClassException异常,因为在反序列化过程中,是先通过无参构造器创造出对象,然后调用各属性的setter给属性设置值的。
同时需要指出的是,假如一个类没有实现Serializable接口或者Externalizable接口,则在序列化该类实例时会报java.io.NotSerializableException异常。更进一步,假如该类没有被transient修饰的非静态成员变量所属类型没有实现Serializable接口或者Externalizable接口,则在序列化时也会报java.io.NotSerializableException异常。
transient关键字与序列化、反序列化的更多相关文章
- Java transient关键字序列化时使用小记
1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过 ...
- Java 序列化 transient关键字
Java 序列化 transient关键字 @author 敏敏Alexia 转自:http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 1. tra ...
- transient关键字的用法
本篇博客转自 一直在路上 Java transient关键字使用小记 1. transient的作用及使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,Java ...
- Java transient关键字使用小记
哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...
- 小伙子,你真的搞懂 transient 关键字了吗?
先解释下什么是序列化 我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术. Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将 ...
- Java Serializable的使用和transient关键字使用小记(转载)
一:Serializable 1.持久化的简单介绍: “持久化”意味着对象的“生存时间”并不取决于程序是否正在执行——它存在或“生存”于程序的每一次调用之间.通过序列化一个对象,将其写入磁盘,以后在程 ...
- (转)Java transient关键字使用小记
背景:最近在看java底层的源码实现,看到一个关键字,不是很熟悉,专门做个记录. 原文出处:http://www.importnew.com/21517.html#comment-637072 哎,虽 ...
- 【转】Java transient关键字使用小记
哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...
- Java transient关键字使用小记(转)
哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transi ...
随机推荐
- NDIS中间层驱动实现截获数据包、包过滤功能
1.包截获功能 http://wenku.baidu.com/view/43960751f01dc281e53af055.html 2.包过滤功能 http://wenku.baidu.com/lin ...
- ENCODE:DNA 分子元件的百科全书
ENCODE(DNA分子元件的百科全书)是由国家人类基因研究所(NHGRI)资助的一个国际研究联盟, 该联盟的目标是:建立一份综合的人类基因组功能元件的清单,这些基本元件包括那些直接作用蛋白质和RNA ...
- java后台对json格式数据的解析
Json 和 Jsonlib 的使用 什么是 Json JSON(JvaScript Object Notation)(官网网站:http://www.json.org/)是 一种轻量级的数据交换格式 ...
- java获取Excel的导入
先准备好这2个架包 import java.io.*; import org.apache.commons.io.FileUtils; import org.apache.poi.hssf.userm ...
- 输入框获取焦点后placeholder文字消失、修改placeholder的样式
输入框获取焦点后placeholder文字消失: <input placeholder='' onfocus="this.placeholder=''" onblur=&qu ...
- c#操作json 使用JavaScriptSerializer
需要引用:System.Web.Extensions /// <summary> /// json的信息.保证定义的变量和json的字段一样(也可以使用struct) /// </s ...
- 【C#】记录程序耗时方法
最近写了一个读txt题库然后导入数据库的控制台应用,查看存入数据库耗时 在C#中使用 Stopwatch 命名空间: System.Diagnostics: 使用方法: System.Diagn ...
- UINavigationController + UIScrollView组合,视图尺寸的设置探秘(二)
承接上文,我想把view布局修改为如下模式,让ScrollView长在NavigationBar的下方,这总不会有遮挡的问题了吧: story board内容如下,主要是右侧视图蓝色区域添加了Scro ...
- 502. IPO
Suppose LeetCode will start its IPO soon. In order to sell a good price of its shares to Venture Cap ...
- Python-OpenCV中VideoCapture类的使用
目录 主要记录Python-OpenCV中的VideoCapture类的使用:官方文档: VideoCapture()是用于从视频文件.图片序列.摄像头捕获视频的类: #!/usr/bin/e ...