transient 变量修饰符

探讨Java序列化机制及transient关键字的作用,演示不同情况下变量的序列化行为,包括静态变量和使用Externalizable接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将二进制数据保存到磁盘或者传输网络,磁盘或者网络接收者可以在对象的属类的模板上来反序列化类的对象,达到对象持久化的目的。

transient 关键字总结

1)transient修饰的变量不能被序列化;

2)transient只作用于实现 Serializable 接口;

3)transient只能用来修饰普通成员变量字段;

4)不管有没有 transient 修饰,静态变量都不能被序列化;

 

java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据 成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字 transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的

 

例一:  id 字段上加了 transient 关键字修饰,反序列化出来之后值为 null,说明了被 transient 修饰的变量不能被序列化

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
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());
 
	}
}
 

@Data
EqualsAndHashCode
class User implements Serializable {
 
	private static final long serialVersionUID = 1L;
 
	private String username;
	private transient String id;
 
}

输出结果:

序列化之前
username: Java技术栈
id: javastack
 
序列化之后
username: Java技术栈
id: null

例二:

 username 改为了 public static, 并在反序列化出来之前改变了静态变量的值,结果可以看出序列化之后的值并非序列化进去时的值。

由以上结果分析可知,静态变量不能被序列化,示例2读取出来的是 username 在 JVM 内存中存储的值。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
 
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());
 
	}
}
 

@Data
@EqualsAndHashCode
class User2 implements Serializable {
 
	private static final long serialVersionUID = 1L;
 
	public static String username;
	private transient String id;
 
}

输出结果: 

序列化之前
username: Java技术栈1
id: javastack
 
序列化之后
username: Java技术栈2
id: null

 

例三:

 id 被 transient 修改了,为什么还能序列化出来?那是因为 User3 实现了接口 Externalizable,而不是 Serializable。

在 Java 中有两种实现序列化的方式,Serializable 和 Externalizable,可能大部分人只知道 Serializable 而不知道 Externalizable。

这两种序列化方式的区别是:

实现了 Serializable 接口是自动序列化的,实现 Externalizable 则需要手动序列化,通过 writeExternal 和 readExternal 方法手动进行,这也是为什么上面的 username 为 null 的原因了。

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;

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();
	}
 
}
 

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值