【经验杂谈】一个使用transient不慎带来的坑

前言

说明:如果您对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类中的atomicIntegertransient修饰,因此在对象序列化时会忽略该字段。而反序列化实际上是重新创建了一个对象,因此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));
    }
}

测试结果
在这里插入图片描述

结论:被trasientstatic修饰的字段均无法序列化或反序列化

总结

本文主要介绍了本人在工作中遇到的一个因使用transient关键字不当导致的bug,因此也借机巩固了transient的作用和基本原理。总结:在使用一个特性的时候,需要有深入的理解,否则可能会带来意想不到的问题。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值