网站首页 > java教程 正文
先解释下什么是序列化
我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术。
Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将二进制数据保存到磁盘或者传输网络,磁盘或者网络接收者可以在对象的属类的模板上来反序列化类的对象,达到对象持久化的目的。
更多序列化请参考:《关于Java序列化你应该知道的一切》这篇文章。
什么是 transient?
简单来说就是,被 transient 修饰的变量不能被序列化。
具体来看下面的示例1
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author 来源:Java技术栈
*/
public class TransientTest {
public static void main(String[] args) throws Exception {
User user = new User();
user.setUsername("Java技术栈");
user.setId("javastack");
System.out.println("\n序列化之前");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/user.txt"));
os.writeObject(user);
os.flush();
os.close();
ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/user.txt"));
user = (User) is.readObject();
is.close();
System.out.println("\n序列化之后");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
}
}
/**
* @author 来源:Java技术栈
*/
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private transient String id;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
输出结果:
序列化之前
username: Java技术栈
id: javastack
序列化之后
username: Java技术栈
id: null
示例1在 id 字段上加了 transient 关键字修饰,反序列化出来之后值为 null,说明了被 transient 修饰的变量不能被序列化。
静态变量能被序列化吗?
这个话题也是最近栈长的Java技术栈vip群里面讨论的,大家对这个知识点比较模糊,我就写了这篇文章测试总结一下。
如果你也想加入我们的Java技术栈vip群和各位大牛一起讨论技术,那点击这个链接了解加入吧。
那么,到底静态变量能被序列化吗?废话少说,先动手测试下吧!
示例2:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* @author 来源:Java技术栈
*/
public class TransientStaticTest {
public static void main(String[] args) throws Exception {
User2 user = new User2();
User2.username = "Java技术栈1";
user.setId("javastack");
System.out.println("\n序列化之前");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/user.txt"));
os.writeObject(user);
os.flush();
os.close();
// 在反序列化出来之前,改变静态变量的值
User2.username = "Java技术栈2";
ObjectInputStream is = new ObjectInputStream(new FileInputStream("d:/user.txt"));
user = (User2) is.readObject();
is.close();
System.out.println("\n序列化之后");
System.out.println("username: " + user.getUsername());
System.out.println("id: " + user.getId());
}
}
/**
* @author 来源:Java技术栈
*/
class User2 implements Serializable {
private static final long serialVersionUID = 1L;
public static String username;
private transient String id;
public String getUsername() {
return username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
输出结果:
序列化之前
username: Java技术栈1
id: javastack
序列化之后
username: Java技术栈2
id: null
示例2把 username 改为了 public static, 并在反序列化出来之前改变了静态变量的值,结果可以看出序列化之后的值并非序列化进去时的值。
由以上结果分析可知,静态变量不能被序列化,示例2读取出来的是 username 在 JVM 内存中存储的值。
transient 真不能被序列化吗?
继续来看示例3:
import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
/**
* @author 来源:Java技术栈
*/
public class ExternalizableTest {
public static void main(String[] args) throws Exception {
User3 user = new User3();
user.setUsername("Java技术栈");
user.setId("javastack");
ObjectOutput objectOutput = new ObjectOutputStream(new FileOutputStream(new File("javastack")));
objectOutput.writeObject(user);
ObjectInput objectInput = new ObjectInputStream(new FileInputStream(new File("javastack")));
user = (User3) objectInput.readObject();
System.out.println(user.getUsername());
System.out.println(user.getId());
objectOutput.close();
objectInput.close();
}
}
/**
* @author 来源:Java技术栈
*/
class User3 implements Externalizable {
private static final long serialVersionUID = 1L;
public User3() {
}
private String username;
private transient String id;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public void writeExternal(ObjectOutput objectOutput) throws IOException {
objectOutput.writeObject(id);
}
@Override
public void readExternal(ObjectInput objectInput) throws IOException, ClassNotFoundException {
id = (String) objectInput.readObject();
}
}
输出结果:
null
javastack
示例3的 id 被 transient 修改了,为什么还能序列化出来?那是因为 User3 实现了接口 Externalizable,而不是 Serializable。
在 Java 中有两种实现序列化的方式,Serializable 和 Externalizable,可能大部分人只知道 Serializable 而不知道 Externalizable。
这两种序列化方式的区别是:实现了 Serializable 接口是自动序列化的,实现 Externalizable 则需要手动序列化,通过 writeExternal 和 readExternal 方法手动进行,这也是为什么上面的 username 为 null 的原因了。
transient 关键字总结
1)transient修饰的变量不能被序列化;
2)transient只作用于实现 Serializable 接口;
3)transient只能用来修饰普通成员变量字段;
4)不管有没有 transient 修饰,静态变量都不能被序列化;
好了,栈长花了半天时间,终于整理完了。如果对你有帮助,那就转发分享一下吧!
另外,栈长已经整理了大量 Java 系列核心技术知识点文章,关注Java技术栈阅读吧。
- 上一篇: 详解Java 中 static 的作用
- 下一篇: java.io.File中的四个静态分隔符变量
猜你喜欢
- 2025-01-08 VBA|变量的类型、声明、作用域
- 2025-01-08 西门子S7-1200变量如何使用?局部/全局变量、临时变量、静态变量
- 2025-01-08 长知识了!Java 关键字 transient 还能这么用
- 2025-01-08 「C++学习笔记(十)」理解类中的静态成员变量与静态成员函数
- 2025-01-08 Java程序员必备技能:静态方法的正确使用姿势!
- 2025-01-08 深入探索 Java 复杂泛型:使用与限制全解析
- 2025-01-08 Java类是如何加载的?
- 2025-01-08 CPU眼里的:静态、全局、临时变量
- 2025-01-08 面试官问我什么是JMM
- 2025-01-08 C/C++中的内存四区
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)