Java transient 关键字详解及实例代码

Java transient 关键字

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
 * http://www.manongjc.com/article/1609.html
 */
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
 * http://www.manongjc.com
 */
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。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • JAVA正则表达式 Pattern和Matcher

    1.简介: java.util.regex是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包. 它包括两个类:Pattern和Matcher Pattern 一个Pattern是一个正则表达式经编译后的表现模式. Matcher 一个Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符串展开匹配检查. 首先一个Pattern实例订制了一个所用语法与PERL的类似的正则表达式经编译后的模式,然后一个Matcher实例在这个给定的Pattern实例的模式控制下进行字

  • java中File类的使用方法

    构造函数 复制代码 代码如下: public class FileDemo {     public static void main(String[] args){         //构造函数File(String pathname)         File f1 =new File("c:\\abc\\1.txt");         //File(String parent,String child)         File f2 =new File("c:\\a

  • java写入文件的几种方法分享

    一,FileWritter写入文件 FileWritter, 字符流写入字符到文件.默认情况下,它会使用新的内容取代所有现有的内容,然而,当指定一个true (布尔)值作为FileWritter构造函数的第二个参数,它会保留现有的内容,并追加新内容在文件的末尾. 1. 替换所有现有的内容与新的内容. new FileWriter(file);2. 保留现有的内容和附加在该文件的末尾的新内容. 复制代码 代码如下: new FileWriter(file,true); 追加文件示例 一个文本文件,

  • Java中的transient关键字介绍

    transient说明一个属性是临时的,不会被序列化. 下面是一个Demo,name声明为 transient,不被序列化 package com.zzs.tet; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.

  • JavaScript 下拉菜单实现代码

    JavaScript下拉菜单 * { padding:0; margin:0; } body { font-family:verdana, sans-serif; font-size:small; } #navigation, #navigation li ul { list-style-type:none; } #navigation { margin:20px; } #navigation li { float:left; text-align:center; position:relati

  • 说一说java关键字final和transient

    首先,说说final. final关键字可以修饰变量,方法,类. final变量: 需求: 1 需要一个永不改变的编译时常量 2 一个运行时被初始化的值,不希望被更改 好处:编译时就执行的计算,减轻运行时的负担 扩展: 可以修饰基本类型和引用对象.修饰基本类型的时候,表示数值很定不变.修饰对象引用的时候,一旦引用被初始化指向一个对象,就无法再将它更改指向另一个对象(该对象本身是可以修改的) 空白final final修饰但又没有给出初始值的域 必须在域的的定义或构造器内用表达式给final赋值(

  • java list用法示例详解

    |--List:元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复(角标1上有个3,角标2上也可以有个3)因为该集合体系有索引,  |-- ArrayList:底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)(特点是查询很快,但增删较慢)线程不同步  |-- LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快)  |-- Vector:底层是数组数据结构 线程同步(数组长度是可变的百分之百延长)(无论查询还是增删都很慢,被ArrayList替代了

  • javascript的console.log()用法小结

    console.log 原先是 Firefox 的"专利",严格说是安装了 Firebugs 之后的 Firefox 所独有的调试"绝招". 这一招,IE8 学会了,不过用起来比 Firebugs 麻烦,只有在开启调试窗口(F12)的时候,console.log 才能出结果,不然就报错. 今天看到 Opera 也有个叫 dragonfly 的东东,用这东西查看 DOM,已经可以和 Firebug 媲美,然而还是不能用 console.log.于是有人就提供了这样两句

  • Java transient关键字使用小记

    哎,虽然自己最熟的是Java,但很多Java基础知识都不知道,比如transient关键字以前都没用到过,所以不知道它的作用是什么,今天做笔试题时发现有一题是关于这个的,于是花个时间整理下transient关键字的使用,涨下姿势~~~好了,废话不多说,下面开始:  1. transient的作用及使用方法        我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了

  • java.net.SocketException: Connection reset 解决方法

    自从SEOTcs系统11月份24日更新了一下SEO得分算法以来,一直困扰我的一个问题出现了,java的数据job任务,在执行过程中会经常报以下的错误: "2011-12-03 18:00:32 DefaultHttpClient [INFO] I/O exception (java.net.SocketException) caught when processing request: Connection reset by peer: socket write error2011-12-03

  • JavaScript window.setTimeout() 的详细用法

    js的setTimeout方法用处比较多,通常用在页面刷新了.延迟执行了等等.但是很多javascript新手对setTimeout的用法还是不是很了解.虽然我学习和应用javascript已经两年多了,但是对setTimeout方法,有时候也要查阅资料.今天对js的setTimeout方法做一个系统地总结. setInterval与setTimeout的区别 说道setTimeout,很容易就会想到setInterval,因为这两个用法差不多,但是又有区别,今天一起总结了吧! setTimeo

  • java中transient关键字用法分析

    本文实例分析了java中transient关键字用法.分享给大家供大家参考.具体分析如下: java有个特点就是序列化,简单地来说就是可以将这个类存储在物理空间(当然还是以文件的形式存在),那么当你从本地还原这个文件时,你可以将它转换为它本身.这可以极大地方便网络上的一些操作,但同时,因为涉及到安全问题,所以并不希望把类里面所有的东西都能存储(因为那样,别人可以通过序列化知道类里面的内容),那么我们就可以用上transient这个关键字,它的意思是临时的,即不会随类一起序列化到本地,所以当还原后

随机推荐