Java中的序列化与反序列化——transient(二)

1、概述

大家好,我是欧阳方超。
如果某类中的sensitive字段不想被序列化。可以使用transient关键字修饰该字段,则其值不会被序列化。今天就来看看这个问题。

2、transient 关键字

2.1、transient基本概念

transient 关键字是 Java 语言中的一个修饰符,它可以用来修饰类中的实例变量,表示该变量在进行对象序列化时应该被忽略,不会被保存到序列化的结果中。在反序列化时,该变量会被赋值为变量类型的默认值。
transient关键字可以用于阻止特定字段被序列化。当一个对象被序列化时,transient字段的值不会被保存,所以反序列化后,transient字段的值会被重新初始化(基本类型会设为默认值,对象类型会设为null)。

2.2、transient 关键字的应用案例

在Java中,transient关键字用于标记一个类的成员变量,表示这个变量在序列化过程中不需要被保存。这通常用于标记一些敏感信息,例如密码或密钥,以确保它们不会在序列化后泄露。下面是一个示例:

import java.io.Serializable;

public class User implements Serializable {
    private String username;
    private transient String password; // 标记为transient字段

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}
import java.io.*;

public class Main {
    public static void main(String[] args) {
        User user = new User("tom", "passwrd");
        try {

            FileOutputStream fileOutputStream = new FileOutputStream("D:\\home\\user.txt");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(user);
            objectOutputStream.close();
            System.out.println("Serialized data is saved in user.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            FileInputStream fileInputStream = new FileInputStream("D:\\home\\user.txt");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            user = (User)objectInputStream.readObject();
            System.out.println("username: " + user.getUsername());
            System.out.println("password: " + user.getPassword());

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

上面的程序运行结果为:

Serialized data is saved in user.txt
username: tom
password: null

在上面的示例中,User类实现了Serializable接口,并将password字段标记为transient。在默认情况下,Java的序列化机制只会将非transient字段写入到输出流中,以便在反序列化时恢复对象的状态。因此,如果您有一个transient字段,它将不会被序列化和反序列化,也不会被写入到Java的输出流中。所以在反序列化时password输出的结果为null。

2.3、一个反例

transient修饰的成员变量一定不会被序列化吗?一般情况下是不会被序列化的,然而,可以通过自定义序列化和反序列化方法来手动保存和恢复transient字段的值。在序列化方法中,您可以手动将transient字段的值写入到输出流中(通过 writeObject()方法),而在反序列化方法中,可以手动从输入流中读取transient字段的值(通过readObject()方法)并将其设置回对象中(否则,该字段的值可能会保持null或默认值)。情况下面的代码的运行结果:

import java.io.IOException;
import java.io.Serializable;

public class User implements Serializable {
    private String username;
    private transient String password; // 标记为transient字段

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        out.defaultWriteObject();
        // 在序列化过程中,手动保存password字段
        out.writeObject(password);
    }

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        // 在反序列化过程中,手动恢复password字段
        password = (String) in.readObject();
    }
}
import java.io.*;

public class Main {
    public static void main(String[] args) {
        User user = new User("tom", "passwrd");
        try {

            FileOutputStream fileOutputStream = new FileOutputStream("D:\\home\\user.txt");
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(user);
            objectOutputStream.close();
            System.out.println("Serialized data is saved in user.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            FileInputStream fileInputStream = new FileInputStream("D:\\home\\user.txt");
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            user = (User)objectInputStream.readObject();
            System.out.println("username: " + user.getUsername());
            System.out.println("password: " + user.getPassword());

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行结果为:

Serialized data is saved in user.txt
username: tom
password: passwrd

可以看到虽然password字段使用了transient来修饰,但依然序列化到了文件并从文件恢复出来了,这就是因为我们在User类中自定义了writeObject()方法和readObject()方法,这两个方法起的作用分别是在序列化时将password字段进行保存、在反序列化时将password字段进行恢复。

3、总结

在Java中,transient关键字用于标记一个类的成员变量,表示这个变量在序列化过程中不需要被保存。这通常用于标记一些敏感信息,例如密码或密钥,以确保它们不会在序列化后泄露。注意,通过相关方法(writeObject()、readObject())依然能够将transient成员变量进行序列化和反序列化,其实,如果要实现对特定字段进行精确地序列化及反序列化,可以使用Externalizable接口,Externalizable接口是一种更高级别的序列化接口,它允许您更精确地控制对象的序列化和反序列化过程,详情我们下次见。我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值