java中transient关键字

一、
1、关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。
2、被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化(Externalizable可以实现静态变量序列化)。
3、一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。也可以认为在将持久化的对象反序列化后,被transient修饰的变量将按照普通类成员变量一样被初始化。

我们知道在Java中,对象的序列化可以通过实现两种接口来实现,若操作的是一个Serializable对象,则所有的序列化将会自动进行,若操作的是 一个Externalizable对象,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。

二、
1.Serializable

import java.io.*;

public class Person implements Serializable
{
    private static String name = null;
    private transient int age = 0;

    // 默认的构造函数必须有,而且可见性为public,反序列化会用到。
    // 否则会报java.io.InvalidClassException: Person; no valid constructor错误
    public Person(){}

    Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

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

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    @Override public String toString()
    {
        return "name is " + getName() + " and age is " + getAge();
    }

    /*@Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.write(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String)in.readObject();
        age = in.read();
    }*/
}

测试类:

import java.io.*;

public class Test {


    public static void main(String[] args) throws IOException, ClassNotFoundException
    {
        Person person = new Person("zhangsir", 18);
        System.out.println(person);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d://test.txt"));
        oos.writeObject(person);
        oos.close();

        person.setName("lisi");
        person.setAge(68);
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d://test.txt"));
        Person person1 = (Person) ois.readObject();
        System.out.println(person1);
    }

}

运行结果:
name is zhangsir and age is 18
name is lisi and age is 0

age没有被序列化,name因为静态变量在全局区,本来流里面就没有写入静态变量,静态变量会去全局区查找,而我们的序列化是写到磁盘上的,所以JVM查找这个静态变量的值,是从全局区查找的,而不是磁盘上。person.setName(“lisi”);,被写到了全局区,其实就是方法区,只不过被所有的线程共享的一块空间。

2、Externalizable

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class Person implements Externalizable
{
    private static String name = null;
    private transient int age = 0;

    // 默认的构造函数必须有,而且可见性为public,反序列化会用到。
    // 否则会报java.io.InvalidClassException: Person; no valid constructor错误
    public Person(){}

    Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

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

    public int getAge()
    {
        return age;
    }

    public void setAge(int age)
    {
        this.age = age;
    }

    @Override public String toString()
    {
        return "name is " + getName() + " and age is " + getAge();
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.write(age);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String)in.readObject();
        age = in.read();
    }
}

测试类同上,
运行结果:
name is zhangsir and age is 18
name is zhangsir and age is 18
可见,使用Externalizable接口可以实现对静态变量的序列化。

三、序列化类中serialVersionUID的作用

一般在支持序列化的类中,都会设置一个serialVersionUID(序列化版本号)。这个变量用于在反序列化过程控制是否支持反序列化重构,即是否允许两个不同类的对象进行转化。如果两个类的serialVersionUID不同,那么在反序列化过程中就会报错失败。这个字段的设置,一般有三种情况,分别是默认不指定,手动指定为1L(或者其他固定值),自动生成64位hash值。

如果不在类中显示指定,那么JVM会在编译的时候根据类的名称,属性和方法等自动分配一个默认值。如此每个类的serialVersionUID都是不同的。此种情况下,也就不允许反序列化重构,即一个类对象的序列化结果不允许反序列化成其他类的对象。
如果手动在类中指定该字段的值为1L(或者其他固定值),那么就会出现很多类的serialVersionUID字段是相同的。这种情况,一般是不会有问题的,因为该字段只是控制了多个类是否可以反序列化重构。实际代码中具体反序列化成哪个类,还是依靠编码人员根据自己的逻辑去进行指定的。
该字段也可以使用ide来生成,这种生成的方式与第一种情况相同,所以都是不同的。但是编码人员可以根据业务逻辑去修改该字段。如果需要多个类支持反序列化重构,则修改成相同的serialVersionUID字段就可以了。
所以,从严谨程度上来说,是3>2>1,但是这三种情况,都是允许的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值