java中的读写实际很多都可以算作二进制的读写,但由于对对象和基本数据的读写较为特殊,因此单独拿出来讲。
对象的读写:ObjectInputStream ObjectOutputStream
基本数据的读写:DataInputStream DataOutputStream
把对象或基本数据写到文件里的过程叫序列化(serialize),从文件中读取一个对象或基本数据叫反序列化(deserialize)
大部分类都实现了Serializable接口,自己写的类也可以实现这个接口:
import java.io.*;
class Person implements Serializable
{
String name;
int age;
Person(String name, int age) {
this.name=name;
this.age=age;
}
public String toString() {
return name + "(" + age + ")";
}
}
public class SerializeDemo {
public static void main (String[] args)
throws IOException
{
Person [] ps = {
new Person("Li",18),
new Person("Wang",19)
};
String fileName = "s.temp";
//Serialize
ObjectOutputStream output = new ObjectOutputStream(
new FileOutputStream(fileName) );
for(Person p : ps) output.writeObject(p);
output.close();
//deserialize
ObjectInputStream input = new ObjectInputStream(
new FileInputStream(fileName) );
Person p = null;
try {
while( (p=(Person)input.readObject()) != null ) {
System.out.println(p);
}
} catch(ClassNotFoundException ex) {}
catch(EOFException eofex) {}
input.close();
}
}
implements Serializable后eclipse会提醒:The serializable class XXX does not declare a static final serialVersionUID field of type long
那么什么是serialVersionUID?
序列化操作的时候系统会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。
当实现java.io.Serializable接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的。
如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。
serialVersionUID有两种显示的生成方式:
一是默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL;
关于重写的toString方法:与序列化无关,而用于打印对象时显示。如果不重写,则使用父类的toString方法:返回的是一个字符串,它的值等于:getClass().getName() + '@' + Integer.toHexString(hashCode())