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 ...
随机推荐
- Linux网络服务管理命令
netstat命令 示例:查看指定的服务是否开启netstat | grep ssh | grep -v grep 网络下载器————wget wget是一个Linux环境下用于从WWW上提取文件的工 ...
- Comparator 排序
例1: import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import ja ...
- leetcode mergeKsortedlink
代码:这个代码是有问题的,问题的产生是map中不能存放相同的值. #include<iostream> #include<vector> #include<cmath&g ...
- easyUI 展开DataGrid里面的行显示详细信息
http://blog.csdn.net/yanghongchang_/article/details/7854156原著 datagrid 可以改变它的view(视图)去显示不同的效果.使用详细视图 ...
- linux 进程间通信机制(IPC机制)一总览
1.作用:进程间通信机制(Inter Process Communication,IPC),这些IPC机制的存在使UNIX在进程通信领域手段相当丰富,也使得程序员在开发一个由多个进程协作的任务组成的系 ...
- Flink on Yarn模式启动流程分析
此文已由作者岳猛授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Flink On Yarn 架构 Paste_Image.png 前提条件首先需要配置YARN_CONF_DI ...
- CHNS类
NS类集合介绍 1.常用部分 NSDictionary NSString NSArray 数组 NSTimer 定时器 NSRange 范围 NSNotification 2.网络相关 NSURLCo ...
- 10、OpenCV Python 图像二值化
__author__ = "WSX" import cv2 as cv import numpy as np #-----------二值化(黑0和白 255)---------- ...
- 【Python OpenGL】【2】第一个三角形(Pyopengl)
根据顶点缓存来生成图元(Python OpenGL) 原文(英文链接)http://ogldev.atspace.co.uk/www/tutorial03/tutorial03.html __auth ...
- P1527 [国家集训队]矩阵乘法
\(\color{#0066ff}{ 题目描述 }\) 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. \(\color{#0066ff}{输入格式}\) 第一行两个数N,Q ...