一 概述
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* A cache of the last value returned by toString. Cleared
* whenever the StringBuffer is modified.
*/
private transient char[] toStringCache;
}
StringBuffer源码中存在一个toStringCache数组使用transient关键字修饰,而且给出的注释是
A cache of the last value returned by toString. Cleared whenever the StringBuffer is modified。
toString返回最后一个值的缓存,无论何时,当StringBuffer被修改时会被去除。
二 关键字transient
了解关键字transient之前,我们应该先了解一个重要的概念——Java中的序列化机制:在Java中对象的序列化指的是将对象转化成字节序列进行表示。该字节序列包含该对象的数据,有关对象的类型的信息和存储在对象中数据的类型。一个序列化后的对象可以被写到数据库或者文件中,也可以用于网络传输,一般当我们使用缓存cache(注:当内存空间不够有可能会本地存储到硬盘)或者远程过程调用RPC(网络传输)的时候,经常需要让我们的实体类实现Serializable接口,使得其序列化。
将序列化对象写入文件后,我们可以从文件中将其读出来,并将其进行反序列化,这样原来序列化的对象的类型信息,对象的数据,以及对象中的数据类型可以用来在内存中新建对象。
对象的序列化与反序列化的过程都是Java虚拟机(JVM)独立的,所以我们可以将一个平台序列化的对象放到另一个完全不同的平台上进行反序列化。
类 ObjectInputStream 和 ObjectOutputStream 是高层次的数据流,它们包含反序列化和序列化对象的方法。
ObjectOutputStream 类包含很多写方法来写各种数据类型,但是一个特别的方法例外:
public final void writeObject(Object x) throws IOException
上面的方法序列化一个对象,并将它发送到输出流。
类 ObjectInputStream 类包含如下反序列化一个对象的方法:
public final Object readObject() throws IOException, ClassNotFoundException
该方法从流中取出下一个对象,并将对象反序列化。它的返回值为Object,因此,你需要将它转换成合适的数据类型。
关键字transient: 其实就是使得被其修饰的字段在序列化过程中不被序列化,可以将无需序列化的字段Filter掉从而能够节省内存或存储空间。
为了更好的突出,transient关键字在序列化中起的作用,给出下列代码示例:
package com.apple.family.testkeytransient;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Rectangle implements Serializable{
private static final long serialVersionUID = 2763654297152416310L;
private Integer width;
private Integer height;
private transient Integer area;
public Rectangle (Integer width, Integer height){
this.width = width;
this.height = height;
this.area = width * height;
}
public void setArea(){
this.area = this.width * this.height;
}
@Override
public String toString(){
StringBuffer sb = new StringBuffer(40);
sb.append("width : ");
sb.append(this.width);
sb.append("\nheight : ");
sb.append(this.height);
sb.append("\narea : ");
sb.append(this.area);
return sb.toString();
}
}
public class TransientExample{
public static void main(String args[]) throws Exception {
Rectangle rectangle = new Rectangle(3,4);
System.out.println("1.原始对象\n"+rectangle);
// 往流写入对象,会实现对象的序列化
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("rectangle"));
o.writeObject(rectangle);
o.close();
// 从流读取对象,会实现对象的反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream("rectangle"));
Rectangle rectangle1 = (Rectangle)in.readObject();
System.out.println("2.反序列化后的对象\n"+rectangle1);
// 为 area 重新赋值
rectangle1.setArea();
System.out.println("3.恢复成原始对象\n"+rectangle1);
in.close();
}
}
执行结果如下:
1.原始对象
width : 3
height : 4
area : 12
2.反序列化后的对象
width : 3
height : 4
area : null //由于transient关键字修饰了area字段,所以序列化时被Filter了,所以反序列化时为null
3.恢复成原始对象
width : 3
height : 4
area : 12
Process finished with exit code 0
综上所述,transient关键字修饰的成员变量可以在该对象被序列化的过程中回被过滤,在反序列化时对应的字段值为null。