transient关键字详解

在看一篇关于多线程环境下SimpleDateFormat线程不安全的问题,一般我们都知道多线程下这个是不安全,但是为什么不安全不太清楚,我在看的这篇文章讲的比较透彻,我根据文章中讲结合SimpleDateFormat源码简单看了下,发现了里面有些成员变量被transient关键字修饰了,以前还没遇到过这个关键字,就大概了解了下,发现还是比较有用的。现总结下。

一、简单介绍

transient是短暂的意思。对于transient 修饰的成员变量,在类的实例对象的序列化处理过程中会被忽略。 因此,transient变量不会贯穿对象的序列化和反序列化,生命周期仅存于调用者的内存中而不会写到磁盘里进行持久化。

上面讲的在对象序列化过程中,被transient 修饰的成员变量会被忽略。可能大家都知道序列化,就是实体类实现Serializable接口嘛!

但是什么是序列化呢?具体什么样的操作才是序列化呢?

Java中对象的序列化指的是将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据和信息,一个序列化后的对象可以被写到数据库或文件中,也可用于网络传输。

说直白点,就是对象在经过各种流(InputStream/OutputStream)传输时会转换为字节。这个过程就是序列化。

二、transient的作用

在序列化对象时,对于一些特殊的数据成员(如用户的密码,银行卡号等),为了在传输过程中不传输这些敏感信息,我们不想用序列化机制来保存它。为了在一个特定对象的一个成员变量上关闭序列化,可以在这个成员变量前加上关键字transient。

三、上代码

    实体类:
package com.lsl.exam.entity;
 
 
import com.baomidou.mybatisplus.annotation.TableName;
 
import java.io.Serializable;
 
@TableName("users")
public class User implements Serializable {
    private static final long serialVersionUID = 8983061158385445440L;
 
    private String userid;
    private String username;
    //被transient关键字修饰
    private transient String userpwd;
    private String truename;
    private String classid;
 
    public String getUserid() {
        return userid;
    }
 
    public void setUserid(String userid) {
        this.userid = userid;
    }
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public String getUserpwd() {
        return userpwd;
    }
 
    public void setUserpwd(String userpwd) {
        this.userpwd = userpwd;
    }
 
    public String getTruename() {
        return truename;
    }
 
    public void setTruename(String truename) {
        this.truename = truename;
    }
 
    public String getClassid() {
        return classid;
    }
 
    public void setClassid(String classid) {
        this.classid = classid;
    }
 
    @Override
    public String toString() {
        return "User{" +
                "userid='" + userid + '\'' +
                ", username='" + username + '\'' +
                ", userpwd='" + userpwd + '\'' +
                ", truename='" + truename + '\'' +
                ", classid='" + classid + '\'' +
                '}';
    }
}

测试类:

package com.lsl.exam.utils;
 
import com.lsl.exam.entity.User;
 
import java.io.*;
 
public class SdfTest {
 
 
    public static void main(String[] args) {
 
        User user = new User();
        user.setClassid("1");
        user.setUserid("001");
        user.setUsername("小明");
        user.setUserpwd("123456");
        user.setTruename("王小明");
 
        System.out.println("序列化前username="+ user.getUsername());
        System.out.println("序列化前userpwd="+ user.getUserpwd());
 
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/aa.txt"));
            //将user对象写入aa.txt
            os.writeObject(user);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
 
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("d:/aa.txt"));
            User uu = (User) in.readObject();
            in.close();
 
            System.err.println("返序列化后username=" + uu.getUsername());
            System.err.println("返序列化后userpwd=" + uu.getUserpwd());
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
}

输出结果:
在这里插入图片描述
这里提出一个疑问:

如果先把实体类User转成string,然后在写入文件,在从文件读取出来,被transient的userPwd还能读取到内容吗?

还是直接上代码看结果吧!

package com.lsl.exam.utils;
 
import com.lsl.exam.entity.User;
 
import java.io.*;
 
public class SdfTest {
 
 
    public static void main(String[] args) {
 
        User user = new User();
        user.setClassid("1");
        user.setUserid("001");
        user.setUsername("小明");
        user.setUserpwd("123456");
        user.setTruename("王小明");
 
        System.out.println("序列化前username="+ user.getUsername());
        System.out.println("序列化前userpwd="+ user.getUserpwd());
 
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d:/aa.txt"));
            //将user对象写入aa.txt
            os.writeObject(user);
            os.flush();
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
 
 
        try {
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("d:/aa.txt"));
            User uu = (User) in.readObject();
            in.close();
 
            System.err.println("返序列化后username=" + uu.getUsername());
            System.err.println("返序列化后userpwd=" + uu.getUserpwd());
        } catch (Exception e) {
            e.printStackTrace();
        }
 
 
        String filePath = "d:/bb.txt";
        String userStr = user.toString();
//        try {
//
//            BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
//            writer.write(userStr);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
 
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {
            writer.write(userStr);
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        //写文件也可以利用PrintWriter
//        try (PrintWriter writer = new PrintWriter(new FileWriter(filePath))) {
//            writer.println(userStr);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
 
 
        try {
 
            BufferedReader reader = new BufferedReader(new FileReader(filePath));
            String line = "";
            while ((line = reader.readLine()) != null){
 
                System.err.println("从文件读取的内容2:" + line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
 
    }
}

结果截图:
在这里插入图片描述

四、总结

1、一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法被访问。

2、transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。

3、一个静态变量不管是否被transient修饰,均不能被序列化(如果反序列化后类中static变量还有值,则值为当前JVM中对应static变量的值)。序列化保存的是对象状态,静态变量保存的是类状态,因此序列化并不保存静态变量。

4、只有对象直接通过流传输时,才是序列化操作。如果把对象通过tostring方法转字符串在传输,就不是序列化了,也就是transient修饰的也会读取到值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值