本文共 4895 字,大约阅读时间需要 16 分钟。
原创作品,允许转载,转载时请务必以超链接形式标明文章 、作者信息和本声明。否则将追究法律责任。
1、transient关键字只能修饰变量( 瞬态变量 ),而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。
2、 被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化 静态变量:我们可以将类级别的变量声明为static。静态变量是属于类的,而不是属于类创建的对象或实例。因为静态变量被类的所有实例共用,所以非线程安全的。通常静态变量还和关键字final一起用,作为所有对象共用的资源或常量。 3、一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。也可以认为在将持久化的对象反序列化后,被transient修饰的变量将按照普通类成员变量一样被初始化。 如下面的例子 package com.kkoolerter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; public class Main implements Serializable { private static final long serialVersionUID = -5836283489677344417L; private transient int classValue = 10; private transient Date date = new Date(); private transient static int staticValue = 10; public static void main(String[] args) throws Exception { Main m = new Main(); m.classValue = 11; Main.staticValue = 11; ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream( new File("0xjh000"))); out.writeObject(m); out.close(); ObjectInputStream in = new ObjectInputStream(new FileInputStream( new File("0xjh000"))); Main m1 = (Main) in.readObject(); in.close(); System.out.println(m1.classValue); System.out.println((m1.date == null ? "date is null" : "date is not null")); } } 程序将输出: 0 date is null 这就说明了一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。 思考一下下面的例子: package com.kkoolerter; 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; 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("ext0000"))); out.writeObject(et); ObjectInput in = new ObjectInputStream(new FileInputStream(new File( "ext0000"))); ExternalizableTest et1 = (ExternalizableTest) in.readObject(); System.out.println(et1.content); out.close(); in.close(); } } 程序运行后将输出如下结果: 哈哈~我将会被序列化,不管我是是否被transient关键字修饰 这是为什么呢,不是说类的变量被transient关键字修饰以后将不能序列化了吗? 我们知道在Java中,对象的序列化可以通过 实现两种接口来实现,若操作的是一个Serializable对象,则所有的序列化将会自动进行,若操作的是 一个Externalizable对象,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。 因此第二个例子输出的是变量content初始化的内容,而不是null。 java关键字Transient 转自http://horst.sun.blog.163.com/blog/static/348849612007614494492/ 翻译自http://www.devx.com/tips/Tip/13726。 Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想 用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。 transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。 首先,让我们看一些Java serialization的代码: public class LoggingInfo implements java.io.Serializable { private Date loggingDate = new Date(); private String uid; private transient String pwd; LoggingInfo(String user, String password) { uid = user; pwd = password; } public String toString() { String password=null; if(pwd == null) { password = "NOT SET"; } else { password = pwd; } return "logon info: \n " + "user: " + uid + "\n logging date : " + loggingDate.toString() + "\n password: " + password; } } 现在我们创建一个这个类的实例,并且串行化(serialize)它 ,然后将这个串行化对象写如磁盘。 LoggingInfo logInfo = new LoggingInfo("MIKE", "MECHANICS"); System.out.println(logInfo.toString()); try { ObjectOutputStream o = new ObjectOutputStream( new FileOutputStream("logInfo.out")); o.writeObject(logInfo); o.close(); } catch(Exception e) { //deal with exception} To read the object back, we can write try { ObjectInputStream in =new ObjectInputStream( new FileInputStream("logInfo.out")); LoggingInfo logInfo = (LoggingInfo)in.readObject(); System.out.println(logInfo.toString()); } catch(Exception e) { //deal with exception} 如果我们运行这段代码,我们会注意到从磁盘中读回(read——back (de-serializing))的对象打印password为"NOT SET"。这是当我们定义pwd域为transient时,所期望的正确结果。 现在,让我们来看一下粗心对待transient域可能引起的潜在问题。假设我们修改了类定义,提供给transient域一个默认值, 代码如下: public class GuestLoggingInfo implements java.io.Serializable { private Date loggingDate = new Date(); private String uid; private transient String pwd; GuestLoggingInfo() { uid = "guest"; pwd = "guest"; } public String toString() { //same as above } } 现在,如果我们穿行化GuestLoggingInfo的一个实例,将它写入磁盘,并且再将它从磁盘中读出,我们仍然看到读回的对象打印password 为 "NOT SET"。当从磁盘中读出某个类的实例时,实际上并不会执行这个类的构造函数, 而是载入了一个该类对象的持久化状态,并将这个状态赋值给该类的另一个对象。