Java
transient声明一个实例变量,当对象存储时,它的值不需要维持。

作用

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。

验证

  1. import java.io.*;
  2. public class TestTransient {
  3. static class User implements Serializable {
  4. String name;
  5. int age;
  6. transient int transient_age;
  7. String sex;
  8. }
  9. public static void main(String[] args) throws IOException, ClassNotFoundException {
  10. User user = new User();
  11. user.age = 12;
  12. user.transient_age = 12;
  13. user.name = "小丸子";
  14. user.sex = "nv";
  15. System.out.println("age:" + user.age);
  16. System.out.println("transient_age:" + user.transient_age);
  17. System.out.println("name:" + user.name);
  18. System.out.println("sex:" + user.sex);
  19. System.out.println("----------------序列化+反序列化----------------");
  20. // 序列化后写入缓存
  21. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  22. ObjectOutputStream oos = new ObjectOutputStream(baos);
  23. oos.writeObject(user);
  24. oos.flush();
  25. oos.close();
  26. byte[] buf = baos.toByteArray();
  27. // 从缓存中读取并执行反序列化
  28. ByteArrayInputStream bais = new ByteArrayInputStream(buf);
  29. ObjectInputStream ois = new ObjectInputStream(bais);
  30. User u = (User) ois.readObject();
  31. System.out.println("age:" + u.age);
  32. System.out.println("transient_age:" + u.transient_age);
  33. System.out.println("name:" + u.name);
  34. System.out.println("sex:" + u.sex);
  35. }
  36. }

结果输出

  1. age:12
  2. transient_age:12
  3. name:小丸子
  4. sex:nv
  5. ----------------序列化+反序列化----------------
  6. age:12
  7. transient_age:0
  8. name:小丸子
  9. sex:nv

扩展

Exteranlizable

Java序列化提供两种方式。一种是实现Serializable接口。另一种是实现Exteranlizable接口。Externalizable接口是继承于Serializable,需要重写writeExternalreadExternal方法,它的效率比Serializable高一些,并且可以决定哪些属性需要序列化(即使是transient修饰的),但是对大量对象,或者重复对象,则效率低。

ArrayList中的transient

下面是ArrayList中的一段代码

  1. /**
  2. * ArrayList 的元素存储在其中的数组缓冲区。ArrayList 的容量就是这个数组缓冲
  3. * 区的长度。添加第一个元素时,任何带有 elementData ==
  4. * DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都将扩展为
  5. * DEFAULT_CAPACITY。
  6. */
  7. transient Object[] elementData; // non-private to simplify nested class access

ArrayList提供了自定义的wirteObjectreadObject方法:

  1. /**
  2. * Save the state of the <tt>ArrayList</tt> instance to a stream (that
  3. * is, serialize it).
  4. *
  5. * @serialData The length of the array backing the <tt>ArrayList</tt>
  6. * instance is emitted (int), followed by all of its elements
  7. * (each an <tt>Object</tt>) in the proper order.
  8. */
  9. private void writeObject(java.io.ObjectOutputStream s)
  10. throws java.io.IOException{
  11. // Write out element count, and any hidden stuff
  12. int expectedModCount = modCount;
  13. s.defaultWriteObject();
  14. // Write out size as capacity for behavioural compatibility with clone()
  15. s.writeInt(size);
  16. // Write out all elements in the proper order.
  17. for (int i=0; i<size; i++) {
  18. s.writeObject(elementData[i]);
  19. }
  20. if (modCount != expectedModCount) {
  21. throw new ConcurrentModificationException();
  22. }
  23. }
  24. /**
  25. * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
  26. * deserialize it).
  27. */
  28. private void readObject(java.io.ObjectInputStream s)
  29. throws java.io.IOException, ClassNotFoundException {
  30. elementData = EMPTY_ELEMENTDATA;
  31. // Read in size, and any hidden stuff
  32. s.defaultReadObject();
  33. // Read in capacity
  34. s.readInt(); // ignored
  35. if (size > 0) {
  36. // be like clone(), allocate array based upon size not capacity
  37. int capacity = calculateCapacity(elementData, size);
  38. SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
  39. ensureCapacityInternal(size);
  40. Object[] a = elementData;
  41. // Read in all elements in the proper order.
  42. for (int i=0; i<size; i++) {
  43. a[i] = s.readObject();
  44. }
  45. }
  46. }

这里定义elementDatatransient是为了防止数据重复被写入磁盘,节省空间。
如果对象声明了readObjectwriteObject方法,对象在被序列化的时候会执行对象的readObjectwriteObject方法。

静态属性

静态属性,无论是否被transient修饰,都不会被序列化。