`

Java_transient

    博客分类:
  • Java
 
阅读更多

via: http://www.cnblogs.com/lanxuezaipiao/p/3369962.html 

1. transient的作用及使用方法

      我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。

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

      总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

 

示例code如下:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @description 使用transient关键字不序列化某个变量
 *        注意读取的时候,读取数据的顺序一定要和存放数据的顺序保持一致
 *        
 * @author Alexia
 * @date  2013-10-15
 */
public class TransientTest {
    public static void main(String[] args) {
        User user = new User();
        user.setUsername("Alexia");
        user.setPasswd("123456");
        System.out.println("read before Serializable: ");
        System.out.println("username: " + user.getUsername());
        System.err.println("password: " + user.getPasswd());
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("C:/user.txt"));
            os.writeObject(user); // 将User对象写进文件
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            ObjectInputStream is = new ObjectInputStream(new FileInputStream("C:/user.txt"));
            user = (User) is.readObject(); // 从流中读取User的数据
            is.close();
            System.out.println("\nread after Serializable: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class User implements Serializable {
    private static final long serialVersionUID = 8294180014912103005L;  
    private String username;
    private transient String passwd;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPasswd() {
        return passwd;
    }
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
}
输出为:
read before Serializable: 
username: Alexia
password: 123456

read after Serializable: 
username: Alexia
password: null
密码字段为null,说明反序列化时根本没有从文件中获取到信息。

2. transient使用小结

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

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

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

第三点可能有些人很迷惑,因为发现在User类中的username字段前加上static关键字后,程序运行结果依然不变,即static类型的username也读出来为“Alexia”了,这不与第三点说的矛盾吗?实际上是这样的:第三点确实没错(一个静态变量不管是否被transient修饰,均不能被序列化),反序列化后类中static型变量username的值为当前JVM中对应static变量的值,这个值是JVM中的不是反序列化得出的,不相信?好吧,下面我来证明:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * @description 使用transient关键字不序列化某个变量
 *        注意读取的时候,读取数据的顺序一定要和存放数据的顺序保持一致
 * @author Alexia
 * @date  2013-10-15
 */
public class TransientTest {
    public static void main(String[] args) {
        User user = new User();
        user.setUsername("Alexia");
        user.setPasswd("123456");
        System.out.println("read before Serializable: ");
        System.out.println("username: " + user.getUsername());
        System.err.println("password: " + user.getPasswd());
        try {
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("C:/user.txt"));
            os.writeObject(user); // 将User对象写进文件
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            // 在反序列化之前改变username的值
            User.username = "jmwang";
            
            ObjectInputStream is = new ObjectInputStream(new FileInputStream("C:/user.txt"));
            user = (User) is.readObject(); // 从流中读取User的数据
            is.close();
            
            System.out.println("\nread after Serializable: ");
            System.out.println("username: " + user.getUsername());
            System.err.println("password: " + user.getPasswd());
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class User implements Serializable {
    private static final long serialVersionUID = 8294180014912103005L;  
    public static String username;
    private transient String passwd;
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPasswd() {
        return passwd;
    }
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

}
运行结果为:
read before Serializable: 
username: Alexia
password: 123456

read after Serializable: 
username: jmwang
password: null
这说明反序列化后类中static型变量username的值为当前JVM中对应static变量的值,为修改后jmwang,而不是序列化时的值Alexia。

3. transient使用细节——被transient关键字修饰的变量真的不能被序列化吗?

思考下面的例子:

import java.io.Externalizable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

/**
 * @descripiton Externalizable接口的使用
 * @author Alexia
 * @date 2013-10-15
 *
 */
public class ExternalizableTest implements Externalizable {
    private transient String content = "是的,我将会被序列化,不管我是否被transient关键字修饰";
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(content);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        content = (String) in.readObject();
    }
    public static void main(String[] args) throws Exception {
        ExternalizableTest et = new ExternalizableTest();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(new File("test")));
        out.writeObject(et);
        ObjectInput in = new ObjectInputStream(new FileInputStream(new File("test")));
        et = (ExternalizableTest) in.readObject();
        System.out.println(et.content);
        out.close();
        in.close();
    }
}

content变量会被序列化吗?好吧,我把答案都输出来了,是的,运行结果就是:

是的,我将会被序列化,不管我是否被transient关键字修饰

这是为什么呢,不是说类的变量被transient关键字修饰以后将不能序列化了吗?

      我们知道在Java中,对象的序列化可以通过实现两种接口来实现,若实现的是Serializable接口,则所有的序列化将会自动进行,若实现的是Externalizable接口,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。因此第二个例子输出的是变量content初始化的内容,而不是null。

分享到:
评论

相关推荐

    Java_transient关键字

    ### Java中的transient关键字详解 在Java编程语言中,`transient`关键字是一个非常重要的概念,主要用于对象序列化过程中对特定变量的控制。当一个类实现了`Serializable`接口时,其对象可以被序列化为一个持久化的...

    Note_scalad.tar.gz

    Java_Transient Java_URLConnection_File_Download Java_Volatile Java_jmap_histo_pid Java_jmeter_server_polling_pressure_test Java_jstack Linux_Copy_On_Write Linux_Hydra Linux_Pip Linux_Redis_Make Linux_...

    Java中的transient关键字.doc

    Java 中的 transient 关键字 在 Java 编程中,transient 关键字是一个非常重要的概念,它用来说明一个属性是临时的,不会被序列化。在 Java 中,序列化是指将对象的状态信息转换为字节流的过程,以便于对象在网络上...

    1_Effective_Java_2nd_Edition_proglib_java_Joshua_

    9. **序列化**:针对Java的序列化机制, Bloch提出了一些注意事项,如实现Serializable接口的潜在风险,以及如何使用transient和serialVersionUID来控制序列化行为。 10. **最后但同样重要的是,持续学习和改进**:...

    java关键字transient

    在Java编程语言中,`transient`是一个非常重要的关键字,它与对象持久化和序列化密切相关。当一个字段被声明为`transient`时,它表明该字段的值不会随着对象的序列化而保存。这通常用于那些不希望或者不需要在序列化...

    Java之transient关键字.Java

    在Java编程语言中,`transient`关键字是一个非常重要的特性,它用于标记对象的某个成员变量不应该被序列化。当你创建一个可序列化的类(通过实现`Serializable`接口)时,如果你不想某些字段在序列化过程中被保存或...

    java作业13_java_

    在Java编程语言中,序列化和反序列化是两个重要的概念,主要应用于对象的状态持久化以及网络传输。本文将深入探讨这两个概念,并结合"java作业13"的实践背景进行详细解析。 首先,序列化(Serialization)是将一个...

    Java关键字Transient与串行化

    在Java编程语言中,`transient`关键字与对象的序列化(serialization)机制密切相关,它在处理对象状态的持久化时扮演着关键角色。本文将深入探讨`transient`关键字的功能、用途以及它如何影响Java对象的序列化过程。 ...

    transient Java语言的关键字

    transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,

    java_性能调优.pdf

    在《java_性能调优.pdf》这份文档中,我们可以提取出一系列关于Java性能调优的知识点,包括但不限于Java语言基础、集合框架、异常处理、设计模式、JDBC使用、I/O操作、多线程编程、JVM内存管理、JSP和Servlet等。...

    Java_序列化的高级认识

    ### Java序列化的高级认识 Java序列化作为Java技术体系中的一个重要组成部分,其核心功能在于能够将Java对象转换成字节流,从而实现对象的持久化存储或是通过网络传输。然而,序列化的应用远不止于此,它还涉及到一...

    java_JAVA电子教案.pdf

    `super`, `switch`, `synchronized`, `this`, `throw`, `throws`, `transient`, `true`, `try`, `void`, `volatile`, `while`。这些关键字在编程中具有特殊含义,不能用作变量名或类名。标识符是用来命名变量、类、...

    Java_英文面试题

    Java编程语言在面试中常常涉及各种技术点,包括序列化、布局管理器、同步机制、集合API、迭代器以及抽象类与接口的区别等。以下是对这些知识点的详细解释: 1. **临时变量(Transient Variable)**: - `transient...

    Java_英文面试题_经典

    `transient`关键字在Java中用于标记一个字段,表示这个字段的数据不应该被序列化。如果在一个实现了Serializable接口的类中声明了一个变量为transient,当该类被写入ObjectStream时,这个变量的值不会被写入流中。...

    重难点之java_JAVA电子教案.pdf

    `long`, `native`, `new`, `null`, `package`, `private`, `protected`, `public`, `return`, `short`, `static`, `strictfp`, `super`, `switch`, `synchronized`, `this`, `throw`, `throws`, `transient`, `true...

    java_java考试复习题本科.pdf

    9. Java内存管理:文档中提到了“transient”关键字,它用于Java序列化过程中,表明某个实例字段不应被序列化,即在对象序列化到文件或数据库时会被忽略,对于内存中对象的垃圾回收也有一定的影响。 10. Java程序...

    Java关键字transient

    在Java编程语言中,`transient`是一个非常重要的关键字,它与对象的序列化息息相关。序列化是将一个对象的状态转换为字节流的过程,这样就可以存储或在网络中传输。当我们标记一个字段为`transient`时,意味着该字段...

    MLDN魔乐JAVA_41面向对象题目

    - `transient`:不参与序列化。 - `volatile`:保证多线程环境下的可见性和有序性。 李兴华的这个面向对象题目集很可能涵盖了以上所有概念的实践题目,通过解答这些题目,开发者可以深入理解并熟练掌握Java的面向...

    java_java考试复习题 本科.pdf

    `abstract`用于定义抽象类,`synchronized`用于线程同步,`transient`则用于标记字段不参与序列化。 3. **异常处理**:Java中使用`try-catch`语句块来捕获和处理异常,可以有多个catch块来处理不同类型的异常。`...

Global site tag (gtag.js) - Google Analytics