关键字transient

在序列化的使用中我们常常遇到这样的问题,对于某些类对象进行序列化传输时,它的某些属性不希望被序列化传输,基于保密等方面。这个时候我们只需要在不希望被序列化的属性前面加上transient关键字即可。

举个例子:

构建一个User类

public class User implements Serializable {
     public String name;
     public transient String passwd;  //passwd不希望被序列化,在内存中临时的存在

     public User(String name,String passwd)
     {
        this.name=name;
        this.passwd=passwd;
     }

}

构建一个测试类

public class Test {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        User a=new User("sean","123");
        System.out.println("a's name:"+a.name+" "+"a's passwd:"+a.passwd);

        ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/testtransient.txt"));
        os.writeObject(a);
        os.flush();
        os.close();

        ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/testtransient.txt"));
        User b=(User) is.readObject();
        is.close();

        System.out.println("b's name:"+b.name+" "+"b's passwd:"+b.passwd);
    }

}

运行结果:

a's name:sean a's passwd:123
b's name:sean b's passwd:null

从运行结果可以看出,属性passwd不能被序列化,通过反序列化生成的对象b没有密码


小结:

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

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

3、被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。


关于第三点,再举个例子说明:

public class User implements Serializable {
     public String name;
     public static String passwd; //把passwd改为静态变量

     public User(String name,String passwd)
     {
        this.name=name;
        this.passwd=passwd;
     }

}

测试程序不变:

public class Test {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        User a=new User("sean","123");
        System.out.println("a's name:"+a.name+" "+"a's passwd:"+a.passwd);

        ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/testtransient.txt"));
        os.writeObject(a);
        os.flush();
        os.close();

        ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/testtransient.txt"));
        User b=(User) is.readObject();
        is.close();

        System.out.println("b's name:"+b.name+" "+"b's passwd:"+b.passwd);
    }

}

运行结果:

a's name:sean a's passwd:123
b's name:sean b's passwd:123

看到这个结果是不是很奇怪,明明说静态变量不能被序列化,但是对象b依然有passwd,其实原因在于,静态变量确实不能被序列化,passwd变量没有被序列化导出到文件中,但是在反序列化对象b的时候,passwd变量自动从JVM中获取了当前内存中a对象的passwd值。如果不相信,咱们修改一下测试类做个试验:

public class Test {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        User a=new User("sean","123");
        System.out.println("a's name:"+a.name+" "+"a's passwd:"+a.passwd);

        ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/testtransient.txt"));
        os.writeObject(a);
        os.flush();
        os.close();

        a.passwd="456"; //在反序列化前修改对象a的密码为456

        ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/testtransient.txt"));
        User b=(User) is.readObject();
        is.close();

        System.out.println("b's name:"+b.name+" "+"b's passwd:"+b.passwd);
    }

}

运行结果:

a's name:sean a's passwd:123
b's name:sean b's passwd:456

反序列化前将a对象的密码改为456,反序列化后对象b的密码也为456,充分证明了上述观点。

另一个证明办法:

将原来的测试类拆分为两个测试类,如下:

public class Test {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        User a=new User("sean","123");
        System.out.println("a's name:"+a.name+" "+"a's passwd:"+a.passwd);

        ObjectOutputStream os=new ObjectOutputStream(new FileOutputStream("C:/testtransient.txt"));
        os.writeObject(a);
        os.flush();
        os.close();

    }

}
public class Test2 {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {

        ObjectInputStream is=new ObjectInputStream(new FileInputStream("C:/testtransient.txt"));
        User b=(User) is.readObject();
        is.close();

        System.out.println("b's name:"+b.name+" "+"b's passwd:"+b.passwd);

    }

}

分别运行测试类Test和Test2,Test2运行结果如下:

b's name:sean b's passwd:null

因为反序列化过程在另一个程序中,由于内存空间不同,对象b的passwd就不能去获取对象a的passwd值了,输出空密码就暴露了静态变量不能被序列化。

猜你喜欢

转载自blog.csdn.net/lovecaicaiforever/article/details/81607006