transient关键字的意思

transient

java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程

作用

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    transient int size = 0;

    /**
     * Pointer to first node.
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     */
    transient Node<E> last;
    ....
    }

应用场景:使用IO流的ObjectOutputStream来持久化对象时:

package Stream_IntOut;

import classandobject.Person;

import java.io.*;

/**
 * 场景:进行一次网上交易,突然服务器中断,我们必须时时刻刻将交易的相关类的信息保存。
 * 等服务器恢复,我们在重新加载该类,则能恢复之前的交易状态,维持数据不变。
 *
 * 也就是说我们需要能够对类、对象进行保存到硬盘等外设。使得对象持久化。
 * ——ObjectOutputStream
 *
 * public class ObjectOutputStream
 * extends OutputStream
 * implements ObjectOutput, ObjectStreamConstants
 * ObjectOutputStream将Java对象的基本数据类型和对象写入OutputStream。
 * 可以使用ObjectInputStream读取(重构)对象。
 * 可以通过使用流的文件来完成对象的持久存储。 如果流是网络套接字流,则可以在另一个主机或另一个进程中重新构建对象。
 *
 * 只有支持java.io.Serializable接口的对象才能写入流。 每个可序列化对象的类都被编码,包括类的类名和签名,对象的字段和数组的值,
 * 以及从初始对象引用的任何其他对象的闭包。 ——serializableVersionID
 *
 * writeObject方法用于将对象写入流。 任何对象,包括字符串和数组,都是用writeObject编写的。
 * 可以将多个对象或基元写入流中。
 * !!!必须从相应的ObjectInputStream中读取对象,这些对象具有与写入时相同的类型和顺序。 (其—serializableVersionID相同才可以
 * 读取,否则会抛出异常:InvalidClassException
 *
 * 也可以使用DataOutput中的适当方法将基本数据类型写入流中。 也可以使用writeUTF方法编写字符串。
 *
 * 对象的默认序列化机制会写入对象的类,类签名以及所有非瞬态(不用transient标示的)和非静态字段的值。
 * 对其他对象的引用(瞬态或静态字段除外)也会导致这些对象被写入。 使用引用共享机制对对单个对象的多个引用进行编码,
 */

public class Practice12_ObjectOutputStream {
    public static void main(String[]args) throws IOException, ClassNotFoundException {
//        writeObjectDemo();
//        System.out.println("写入Person对象完毕!");
        readObjectDemo();
    }

    public static void readObjectDemo() throws IOException, ClassNotFoundException {
        //ObjectInputStream只能用来读取由ObjectOutputStream写入的对象。
        // 而且要存储对象的serialVersionUID与字节码文件的serialVersionUID相同才可反序列化。读取该对象。
        ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("E:\\Object.txt"));
        Person p = (Person)ooi.readObject();//当对应的serialVersionUID不同,会报错,无法加载保存到硬盘的对象。

        /*
        报错信息
        Exception in thread "main" java.io.InvalidClassException: classandobject.Person;
        local class incompatible: stream classdesc serialVersionUID = 2564213078493790751,
        local class serialVersionUID = -4578207210445382436

        所以一般为了防止当存放了对象,而对类的一些属性修改了。进而导致的ID不一致
        通常使用显示声明ID,当然一般不要修改。
         */
        System.out.println(p.getName()+" :"+p.getAge());
        //接下来演示静态变量无法写入对象时存储到硬盘。
        //将age改为了静态。

        /*
        结果:lisi :0,明明我们存放的不该是lisi 22吗?说明静态变量根本没有存进去。
         */

        //接下来演示transient关键字
        //将age改为 private transient int age;
        /*
         * 结果lisi :0,明明我们存放的不该是lisi 22吗?说明非瞬态的变量根本没有存进去。
         * 所以transient就这个作用。
         * 而当我们有一些变量,我们不想写入对象时将其写入硬盘,但它又不是静态的时候,
         *         我们可以声明它为瞬时的——关键字transient
         */
        ooi.close();
    }

    public static void writeObjectDemo() throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\Object.txt"));//一般以object后缀结尾,表示对象持久化文件。
        oos.writeObject(new Person("lisi",22));//当没有该对象没有实现Serializable接口,就会无法序列化。
        //报错Exception in thread "main" java.io.NotSerializableException: classandobject.Person
        oos.close();
        /*
        注意写入内容是:
        对象的类,类签名以及所有非瞬态(不用transient标示的)和非静态字段的值。
        对其他对象的引用(瞬态或静态字段除外)也会导致这些对象被写入。
        因为静态变量处于方法区的静态方法区,也就是堆中。

        而当我们有一些变量,我们不想写入对象时将其写入硬盘,但它又不是静态的时候,
        我们可以声明它为瞬时的——关键字transient
         */
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章