Java 关键字 transient

序列化与反序列化

学习 transient 关键字之前呢,我们需要先了解一下 序列化反序列化

  • Java提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
  • 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。

举个栗子
你去街上买菜,一般操作都是用塑料袋给包装起来,直到回家要做菜的时候就把菜给拿出来。而这一系列操作就像极了序列化和反序列化!

transient 关键字

作用

让某些被 transient 关键字修饰的成员属性变量不被序列化

使用场景

如果用户有一些密码、薪资等信息,为了安全起见,不希望在网络操作中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

序列化与transient的使用

  • 需要做序列化的对象的类,必须实现序列化接口:Java.lang.Serializable 接口(一个标志接口,没有任何抽象方法),Java 中大多数类都实现了该接口,比如:String,Integer类等。不实现该接口的类进行序列化或反序列化会抛 NotSerializableException 异常
  • 对象流
      ObjectOutputStream->writeObject()方法做序列化操作
      ObjectInputStream->readObject()方法做反序列化操作
  • 被 transient 修饰的成员变量,在序列化的时候其值会被忽略,在被反序列化后, transient 变量的值被设为初始值, 如 int 型的是 0,对象型的是 null
  • transient 关键字只能修饰变量,而不能修饰方法和类
  • final 只是保证变量不能被修改,不影响 transient 对变量的不序列化作用
  • static 修饰的变量不参与序列化,static 的作用域是类而非某个具体对象

代码栗子

实践是检验真理的唯一标准,疑惑的时候最好动手敲一下demo 看看,顺便也能加深理解和记忆。

栗子1→加 transient 与 不加 transient

import java.io.*;

class UserInfo implements Serializable {
    private transient String name;//给name加了transient修饰
    private String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    @Override
    public String toString(){
        return "name=" + name + ";psw=" + psw;
    }
}

public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("小菜", "666");
        System.out.println("序列化前->" + userInfo.toString());

        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("userInfo.txt"));
            outputStream.writeObject(userInfo);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("userInfo.txt"));
            Object o = inputStream.readObject();
            System.out.println("序列化后->" + o);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

执行结果

序列化前->name=小菜;psw=666
序列化后->name=null;psw=666

可见加了 transient 修饰的变量 name 反序列化后是 null,即 name 没有参与序列化。

栗子2→加了 final transient 修饰变量

import java.io.*;

class UserInfo implements Serializable {
    private final transient String name;//给name加了final transient修饰
    private String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    @Override
    public String toString(){
        return "name=" + name + ";psw=" + psw;
    }
}

public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("小菜", "666");
        System.out.println("序列化前->" + userInfo.toString());

        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("userInfo.txt"));
            outputStream.writeObject(userInfo);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("userInfo.txt"));
            Object o = inputStream.readObject();
            System.out.println("序列化后->" + o);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

执行结果

序列化前->name=小菜;psw=666
序列化后->name=null;psw=666

可见加了final transient 修饰的变量 name 反序列化后依然是 null,即 name 没有参与序列化,final 的作用仅是保证变量不能被修改。

栗子3→加了 static transient 修饰变量

import java.io.*;

class UserInfo implements Serializable {
    private static transient String name;//给name加了static transient修饰
    private String psw;

    public UserInfo(String name, String psw) {
        UserInfo.name = name;
        this.psw = psw;
    }

    @Override
    public String toString(){
        return "name=" + name + ";psw=" + psw;
    }

    public void setName(String name) {
        UserInfo.name = name;
    }
}

public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("小菜", "666");
        System.out.println("序列化前->" + userInfo.toString());

        try {
            ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("userInfo.txt"));
            outputStream.writeObject(userInfo);
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            userInfo.setName("xiaocai");//反序列化之前修改 name 的值
            ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("userInfo.txt"));
            Object o = inputStream.readObject();
            System.out.println("序列化后->" + o);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

执行结果

序列化前->name=小菜;psw=666
序列化后->name=xiaocai;psw=666

在反序列化之前修改 name 的值,接着反序列化后,可见 name 是新的值 xiaocai 。即被 static 修饰的变量不参与序列化。这里可能有点疑惑,从文件用 ObjectInputStream 反序列化出来的对象存到新的对象 Object o , 跟上面用 ObjectOutputStream 序列化进文件的对象不是同一个对象了呀,为什么 name 属性会共享了呢?原来 static 的作用域是 而非某个具体对象,name 在 TestTransient 类里边是一个 static 变量,作用域是整个类,值当然是共享的啦。

总结

  • 使用 transient 关键字的好处是节省存储空间,优化程序
  • 被 transient 修饰的字段会重新计算,初始化。

参考与感谢
Java关键字之static、final、transient
java中的transient关键字详解

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值