首页 > java > basic > 24.transient关键字详解

24.transient关键字详解

我在自己的项目中很少使用transient关键字。这个关键字的作用是和序列化相关的。JDK的源码中ArrayList类用到了transient关键字.整理一下这个关键字相关的内容.

1 接口 Serializable

提到transient关键字之前需要先了解Serializable接口. Serializable接口 JDK1.6文档. java.io.Serializable接口中没有任何方法或者字段,仅用于标识可序列化的语义。类通过实现接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。

2 序列化与反序列化

序列化是指将对象的状态信息转换为可以存储或传输的形式的过程。简单理解为,对象转换为字节序列的过程称为对象的序列化;把字节序列恢复为对象的过程称为对象的反序列化。

3 transient关键字

这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。

在实际开发过程中,这个类的有些属性需要序列化,而其他属性不需要被序列化。 例如:一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

3.1 JDK中transient关键字应用举例

ArrayList源码中应用到了transient关键字。

transient Object[] elementData; // non-private to simplify nested class access

elementData是一个缓存数组,通常会预留一些容量,等容量不足时再扩充。扩充空间超过实际数据长度的冗余部分,没有实际意义。不需要进行序列化。所以ArrayList的设计者将elementData设计为transient,然后在writeObject方法中只序列化了实际存储的那些元素,而不是整个数组。

3.2 对象序列化transient关键字应用举例

  • 实现步骤: 1.创建一个简单的类,定义几个成员变量,其中的一个变量设置为transient关键字修饰。 2.创建一个字节输出流,将这个对象序列化,输出到字节数组中。 3.创建一个输入流,从这个字节数组反序列化,实例化这个对象。 4.输出这个对象的属性,查看有transient关键字修饰修饰的变量,和没有这个关键词修饰的变量的区别。

  • 示例代码

package com.dashidan.lesson24;

import java.io.*;

/**
 * 大屎蛋教程网-dashidan.com
 * Java教程基础篇:  24.transient关键字详解
 * 2018/5/26
 */
public class Demo1 {

    static int id = 100;
    static String name = "大屎蛋";
    static String url = "http://dashidan.com";
    static String weather = "晴朗";

    public static void main(String[] args) {

        /** 创建测试对象*/
        TestObject testObject = new TestObject(id, name, url, weather);
        try {
            /** 将对象序列化,输出到byte[]中*/
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
            outputStream.writeObject(testObject);
            outputStream.close();
            byte[] bytes = byteArrayOutputStream.toByteArray();
            byteArrayOutputStream.close();

            /** 将byte[]字节反序列化,转化为对象*/
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
            ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);
            TestObject obj = (TestObject) inputStream.readObject();
            inputStream.close();
            byteArrayInputStream.close();

            /** 输出运行结果*/
            System.out.println(obj.getId());
            System.out.println(obj.getName());
            System.out.println(obj.getUrl());
            System.out.println(obj.getWeather());
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


/**
 * 实现Serializable接口的测试类,其中weather属性被定义transient
 */
class TestObject implements Serializable {

    int id;
    String name;
    String url;
    transient String weather;

    public TestObject(int id, String name, String url, String weather) {
        this.id = id;
        this.name = name;
        this.url = url;
        this.weather = weather;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getUrl() {
        return url;
    }

    public String getWeather() {
        return weather;
    }
}

输出结果

100
大屎蛋
http://dashidan.com
null

从这个输出结果可以看出由transient修饰的变量输出为null,说明没有序列化。

将这个关键字删除,再运行一遍,输出结果:

100
大屎蛋
http://dashidan.com
晴朗

移除这个关键字以后,输出结果中就能反序列出这个属性的值。通过这个简单的例子可以理解transient关键字在序列化与反序列化中的作用。

转载请保留原文链接.