博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java transient关键字使用小结及一些需要注意的细节
阅读量:4071 次
发布时间:2019-05-25

本文共 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"。当从磁盘中读出某个类的实例时,实际上并不会执行这个类的构造函数,   
而是载入了一个该类对象的持久化状态,并将这个状态赋值给该类的另一个对象。
你可能感兴趣的文章
python_configparser(解析ini)
查看>>
selenium学习资料
查看>>
<转>文档视图指针互获
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
javascript传参字符串 与引号的嵌套调用
查看>>
swiper插件的的使用
查看>>
layui插件的使用
查看>>
JS牛客网编译环境的使用
查看>>
9、VUE面经
查看>>
Golang 数据可视化利器 go-echarts ,实际使用
查看>>
mysql 跨机器查询,使用dblink
查看>>
mysql5.6.34 升级到mysql5.7.32
查看>>
dba 常用查询
查看>>
Oracle 异机恢复
查看>>
Oracle 12C DG 搭建(RAC-RAC/RAC-单机)
查看>>
Truncate 表之恢复
查看>>
Oracle DG failover 后恢复
查看>>
mysql 主从同步配置
查看>>