前言
说明:如果您对transient
关键字非常了解或熟悉,请忽略,不喜勿喷。
本文主要介绍本人最近在重构线上代码时,发现组内小伙伴用了
transient
关键字带来的一个问题,因此在这里记录一下,同时巩固一下transient
关键字的作用和原理,如果您对transient
关键字非常了解或熟悉,本文可以跳过不看。
问题复现
说明:本文的序列化主要用了fastjson作为序列化测试工具
pom依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
model类
package com.xfc.experience.testtransient;
import lombok.Data;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 测试model
*
* @author xf.chen
* @date 2021/7/30 23:36 下午
* @since 1.0.0
*/
@Data
public class TransientModel {
/**
* id
*/
private Integer id;
/**
* name
*/
private String name;
/**
* 原子类
*/
private final transient AtomicInteger atomicInteger = new AtomicInteger(1);
/**
* 获取下一个ID
*
* @return id
*/
public Integer nextId() {
return atomicInteger.getAndIncrement();
}
}
测试代码
package com.xfc.experience.testtransient;
import com.alibaba.fastjson.JSON;
import java.util.concurrent.ArrayBlockingQueue;
/**
* transient测试
*
* @author xf.chen
* @date 2021/7/30 23:34 下午
* @since 1.0.0
*/
public class TransientTest {
/**
* 临时容器,模拟分布式缓存
*/
private static final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
public static void main(String[] args) {
final TransientModel transientModel = new TransientModel();
// id = 1
transientModel.setId(transientModel.nextId());
transientModel.setName("test" + transientModel.getId());
final String jsonData = JSON.toJSONString(transientModel);
queue.add(jsonData);
// id =2
transientModel.setId(transientModel.nextId());
transientModel.setName("test" + transientModel.getId());
final String jsonData1 = JSON.toJSONString(transientModel);
queue.add(jsonData1);
final String poll = queue.peek();
// 反序列化
final TransientModel transientModel1 = JSON.parseObject(poll, TransientModel.class);
assert transientModel1 != null;
// 这里应该期望是 id = 3
transientModel1.setId(transientModel1.nextId());
transientModel1.setName("test" + transientModel.getId());
final String jsonData2 = JSON.toJSONString(transientModel1);
queue.add(jsonData2);
// 打印
for (String s : queue) {
System.out.println(s);
}
}
}
执行结果
{"id":1,"name":"test1"}
{"id":2,"name":"test2"}
// 这里期望是3,为什么是1呢?
{"id":1,"name":"test2"}
原因分析
原因:TransientModel类中的
atomicInteger
被transient
修饰,因此在对象序列化时会忽略该字段。而反序列化实际上是重新创建了一个对象,因此TransientModel类中的atomicInteger
是重新创建的AtomicInteger对象,因此又回到了初始值1。
tranisent
是什么,原理是什么?
transient
为java关键字,为变量修饰符,主要作用为在对象被存储时,不需要维持字段的值。仅仅作用于内存操作阶段。如果被序列化,则该字段不会保存
什么序列化和反序列化?
- Java 序列化是指把 Java 对象转换为字节序列的过程;java中需要序列化的对象必须实现
java.io.Serializable
接口,该接口为标记接口,其功能在xxx中已解释,这里不再赘述- 可用于以字节序列的方式存储到磁盘,进行数据持久化
- 可用于以字节序列的方式进行网络传输
- Java 反序列化是指把字节序列恢复为 Java 对象的过程;
Java中还有什么样的字段不会被序列化呢?
- 被
transient
关键字修饰的字段不会被序列化,这个开篇的测试中已经证明 - 被static关键字修饰的字段不会被序列化。测试代码如下
package com.xfc.experience.staticfield;
import com.alibaba.fastjson.JSON;
import com.xfc.experience.model.User;
/**
* 静态字段序列化测试
*
* @author xf.chen
* @date 2021/7/31 7:47 上午
* @since 1.0.0
*/
public class StaticFieldTest {
public static void main(String[] args) {
final User user = new User(1, "xingfei.chen");
// 序列化
final String json = JSON.toJSONString(user);
System.out.println(json);
// 反序列化
System.out.println(JSON.parseObject(json, User.class));
}
}
测试结果
结论:被trasient
、static
修饰的字段均无法序列化或反序列化
总结
本文主要介绍了本人在工作中遇到的一个因使用transient
关键字不当导致的bug,因此也借机巩固了transient
的作用和基本原理。总结:在使用一个特性的时候,需要有深入的理解,否则可能会带来意想不到的问题。