java transient初探

1.关于transient的解释

transient用来表示一个域(对象属性)不是该对象串行化(序列化)的一部分。当一个对象被串行化的时候,transient修饰的变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。

2.实践证明

A.第一步:新建一个其对象可以被序列化的类Book,源码如下:

/**
 * 该类对象可以被序列化
 * @author yuanli
 *
 */
public class Book implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 3173949523199923358L;
	private int id;
	private String name;
	private transient float price;
	
	public Book() {
		super();
	}

	public Book(int id, String name, float price) {
		super();
		this.id = id;
		this.name = name;
		this.price = price;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public float getPrice() {
		return price;
	}

	public void setPrice(float price) {
		this.price = price;
	}
	
	@Override
	public String toString() {
		return "id=" + this.id + ",name=" + this.name + ",price=" + this.price;
	}
}

B.第二步,编写测试类进行测试,代码如下:

public void testTransient() {
		
		try {
			Book book = new Book(1,"aa",12.5f);
			System.out.println("book序列化之前: " + book.toString());
			
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(baos);
			//序列化book对象
			oos.writeObject(book);
			
			//反序列化book对象
			ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
			Book book_serializable = (Book)ois.readObject();
			System.out.println("book反序列化之后:" + book_serializable.toString());
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}


C.第三步,运行,分析执行结果

book序列化之前: id=1,name=aa,price=12.5
book反序列化之后:id=1,name=aa,price=0.0

从执行结果中可以发现,反序列化之后book对象的price属性变为默认值了,实践证明,被transient关键字修饰的域(属性)确实不会被序列化。

 3.困惑之处

通过上面的实践自我感觉已经掌握了transient的用处,然而分析ArrayList源码之后又让我多了几分困惑,部分源码如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer.
     */
    private transient Object[] elementData;

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param   initialCapacity   the initial capacity of the list
     * @exception IllegalArgumentException if the specified initial capacity
     *            is negative
     */
    public ArrayList(int initialCapacity) {
	super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
	this.elementData = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
	this(10);
    }

.......
}

研究发现ArrayList的背后实际上是一个动态数组,private transient Object[] elementData;那为什么要修饰为transient呢?这样岂不是不能被序列化了?我带着疑问进行了测试,结果发现能够正常序列化和反序列化,集合中的元素也不会丢失,如果这样,那岂不与上面的实践结论相矛盾?看到下面的解释后,让我豁然开朗。

 elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量。假如现在实际有了5个元素,而elementData的大小可能是10,那么在序列化时只需要储存5个元素,数组中的最后五个元素是没有实际意义的,不需要储存。所以ArrayList的设计者将elementData设计为transient,然后在writeObject方法中手动将其序列化,并且只序列化了实际存储的那些元素,而不是整个数组


4.再次困惑 

LinkedList的部分代码如下:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    private transient Entry<E> header = new Entry<E>(null, null, null);
    private transient int size = 0;

    /**
     * Constructs an empty list.
     */
    public LinkedList() {
        header.next = header.previous = header;
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param  c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public LinkedList(Collection<? extends E> c) {
	this();
	addAll(c);
    }
    ......
        /**
     * Returns the number of elements in this list.
     *
     * @return the number of elements in this list
     */
    public int size() {
	return size;
    }
    ......
}

研究LinkedList源码发现size和head属性被transient修饰,这样的属性应该不会被序列化,可实践证明可以正常序列化,反序列化后调用size()方法返回的结果同序列化前相同。那么这样设计的目的何在?求解中...............



ss

原文地址:https://www.cnblogs.com/yyuuaannllii/p/3775223.html