package list;
//在ArrayList 源码中有这样的代码
/*
* private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
这是实现Serialiazable接口,并且重写readObject()和writeObject();在实际序列化的时候,会利用反射最终调用到你重写的
writeObject和readObject 来序列化。现在这么一个问题:既然transient 修饰了elementData为什么还会重写呢?
下面解答:
首先看一看transient关键字的作用
我们都知道只要一个类实现了serializable接口,这个类的对象就可以被序列化。然而在实际开发中,我们可能并不需要某些字段的序列化,
所以就可以用transient修饰字段。比如密码。那就是说,这个字段只存在于调用者的内存中而不会被写入磁盘中被持久化。
其次的明白序列化的流程
要序列化一个对象,必须要将其与一个输入输出流联系起来。输出流以保存其状态,输入流恢复其状态。在序列化和反序列化的过程中必须使用下列
准确签名来实现特殊方法。
private void writeObiect(java.io.ObjectOutputStream s)throws java.io.IOException
private void readObject(java.io.ObjectInputStream s)throws java.io.IOException ClassNotFoundException
仔细观察源码可以发现,s.writeObjec(elementData[i])达到向输出流写入对象的目的。
private 那么时候调用呢?
ObjectOutputStream会调用这个类的writeObject方法进行序列化,ObjectInputStream会调用相应的readObject方法进行反序列化。
那么ObjectOutputStream 怎么知道这个类重写了readObject()方法呢?反射!
这时我可以说刚开始问题的答案了:ArrayList 其实是用数组实现的,明白他的扩容机制后便可以知道,它的容量是大于实际存储对象的个数的。
如果说直接序列化的话,就会造成空间浪费。所以会在writeObject()中手动序列化。这样我们就序列化的是实际存储的对象元素。
*/
import java.io.File;
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;
public class AnimalSerializable implements Serializable{
private static final long serialVersionUID = -7461498806905104482L;
public AnimalSerializable() {
}
public AnimalSerializable(int age, String name){
this.age = age;
this.name = name;
}
private int age ;
private String name;
private void writeObject(java.io.ObjectOutputStream s){
try {
s.writeObject(name);
s.writeObject(age);
System.out.println("重写了writeObject");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void readObject(java.io.ObjectInputStream s){
try {
name = (String) s.readObject();
age = (int) s.readObject();
System.out.println("重写了 readObject");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "AnimalSerializable [age=" + age + ", name=" + name + "]";
}
public static void main(String[] args) {
AnimalSerializable animal = new AnimalSerializable(10, "xiaohong");
File file = new File("D:/test.txt");
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(file));
output.writeObject(animal);
ObjectInputStream input = new ObjectInputStream(new FileInputStream(file));
AnimalSerializable anima = (AnimalSerializable) input.readObject();
System.out.println(anima.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}