IO框架(四)对象流、序列化和反序列化
IO框架(四)对象流、序列化和反序列化
目录
对象流的内容和目的
- 对象流:ObjectInputStream/ObjectOutputStream
- 目的:
- 增强了缓冲区功能
- 增强了读写8种基本数据类型和字符串功能
- 能够将内存中的对象写入硬盘,或读取结果为一个对象
- 增强了读写对象的功能:
- readObject() 从流中读取一个对象
- writeObject(Object obj) 向流中写入一个对象
- 使用流传输对象的过程称为序列化、反序列化
ObjectOutputStream(序列化)
ObjectOutputStream方法
| Modifier and Type | Method and Description |
|---|---|
protected void |
annotateClass(类<?> cl) 子类可以实现此方法,以允许类数据存储在流中。 |
protected void |
annotateProxyClass(类<?> cl) 子类可以实现这种方法来存储流中的自定义数据以及动态代理类的描述符。 |
void |
close() 关闭流。 |
void |
defaultWriteObject() 将当前类的非静态和非瞬态字段写入此流。 |
protected void |
drain() 排除ObjectOutputStream中的缓冲数据。 |
protected boolean |
enableReplaceObject(boolean enable) 启用流来替换流中的对象。 |
void |
**flush() ** 刷新流。 |
ObjectOutputStream.PutField |
putFields() 检索用于缓冲要写入流的持久性字段的对象。 |
protected Object |
replaceObject(Object obj) 该方法将允许ObjectOutputStream的可信子类在序列化期间将一个对象替换为另一个对象。 |
void |
reset() 复位将忽略已写入流的任何对象的状态。 |
void |
useProtocolVersion(int version) 指定在编写流时使用的流协议版本。 |
void |
write(byte[] buf) 写入一个字节数组。 |
void |
write(byte[] buf, int off, int len) 写入一个子字节数组。 |
void |
write(int val) 写一个字节。 |
void |
writeBoolean(boolean val) 写一个布尔值。 |
void |
writeByte(int val) 写入一个8位字节。 |
void |
writeBytes(String str) 写一个字符串作为字节序列。 |
void |
writeChar(int val) 写一个16位的字符。 |
void |
writeChars(String str) 写一个字符串作为一系列的字符。 |
protected void |
writeClassDescriptor(ObjectStreamClass desc) 将指定的类描述符写入ObjectOutputStream。 |
void |
writeDouble(double val) 写一个64位的双倍。 |
void |
writeFields() 将缓冲的字段写入流。 |
void |
writeFloat(float val) 写一个32位浮点数。 |
void |
writeInt(int val) 写一个32位int。 |
void |
writeLong(long val) 写一个64位长 |
void |
**writeObject(Object obj) ** 将指定的对象写入ObjectOutputStream。 |
protected void |
writeObjectOverride(Object obj) 子类使用的方法来覆盖默认的writeObject方法。 |
void |
writeShort(int val) 写一个16位短。 |
protected void |
writeStreamHeader() 提供了writeStreamHeader方法,因此子类可以在流中附加或预先添加自己的头。 |
void |
writeUnshared(Object obj) 将“非共享”对象写入ObjectOutputStream。 |
void |
**writeUTF(String str) **此字符串的原始数据写入格式为 modified UTF-8 。 |
ObjectOutputStream构造方法
| Modifier | Constructor and Description |
|---|---|
protected |
**ObjectOutputStream() **为完全重新实现ObjectOutputStream的子类提供一种方法,不必分配刚刚被ObjectOutputStream实现使用的私有数据。 |
|
**ObjectOutputStream(OutputStream out) **创建一个写入指定的OutputStream的ObjectOutputStream。 |
注意:
- 对象要实现Serializable接口才能序列化
- Serializable是一个标记接口,只用来标记该对象可以序列化
举例
类:
//序列化类必须要实现Serializable接口
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
主函数(将对象序列化(写入硬盘)):
public class Demo07 {
public static void main(String[] args) throws Exception{
FileOutputStream fos=new FileOutputStream("D:\\stu.bin");//bin表示二进制文件
ObjectOutputStream oos=new ObjectOutputStream(fos);
//序列化
Student zhangsan=new Student("张三",18);
oos.writeObject(zhangsan);
//关闭
oos.close();
System.out.println("序列化完毕");
}
}
//输出:
序列化完毕
ObjectInputStream(反序列化)
ObjectInputStream方法
| Modifier and Type | Method and Description |
|---|---|
int |
available() 返回可以读取而不阻塞的字节数。 |
void |
close() 关闭输入流。 |
void |
defaultReadObject() 从此流读取当前类的非静态和非瞬态字段。 |
protected boolean |
enableResolveObject(boolean enable) 启用流以允许从流中读取的对象被替换。 |
int |
read() 读取一个字节的数据。 |
int |
read(byte[] buf, int off, int len) 读入一个字节数组。 |
boolean |
readBoolean() 读取布尔值。 |
byte |
readByte() 读取一个8位字节。 |
char |
readChar() 读一个16位字符。 |
protected ObjectStreamClass |
readClassDescriptor() 从序列化流读取类描述符。 |
double |
readDouble() 读64位双倍。 |
ObjectInputStream.GetField |
readFields() 从流中读取持久性字段,并通过名称获取它们。 |
float |
readFloat() 读32位浮点数。 |
void |
readFully(byte[] buf) 读取字节,阻塞直到读取所有字节。 |
void |
readFully(byte[] buf, int off, int len) 读取字节,阻塞直到读取所有字节。 |
int |
readInt() 读取一个32位int。 |
String |
readLine() 已弃用 此方法无法将字节正确转换为字符。 有关详细信息和替代方案,请参阅DataInputStream。 |
long |
readLong() 读64位长。 |
Object |
readObject() 从ObjectInputStream读取一个对象。 |
protected Object |
readObjectOverride() 此方法由ObjectOutputStream的受信任子类调用,该子类使用受保护的无参构造函数构造ObjectOutputStream。 |
short |
readShort() 读取16位短。 |
protected void |
readStreamHeader() 提供了readStreamHeader方法来允许子类读取和验证自己的流标题。 |
Object |
readUnshared() 从ObjectInputStream读取一个“非共享”对象。 |
int |
readUnsignedByte() 读取一个无符号的8位字节。 |
int |
readUnsignedShort() 读取无符号16位短。 |
String |
readUTF() 以 modified UTF-8格式读取字符串。 |
void |
registerValidation(ObjectInputValidation obj, int prio) 在返回图之前注册要验证的对象。 |
protected 类<?> |
resolveClass(ObjectStreamClass desc) 加载本地类等效的指定流类描述。 |
protected Object |
resolveObject(Object obj) 此方法将允许ObjectInputStream的受信任子类在反序列化期间将一个对象替换为另一个对象。 |
protected 类<?> |
resolveProxyClass(String[] interfaces) 返回一个代理类,它实现代理类描述符中命名的接口; 子类可以实现此方法从流中读取自定义数据以及动态代理类的描述符,从而允许它们为接口和代理类使用备用加载机制。 |
int |
skipBytes(int len) 跳过字节。 |
ObjectInputStream构造方法
| Modifier | Constructor and Description |
|---|---|
protected |
**ObjectInputStream() ** 为完全重新实现ObjectInputStream的子类提供一种方法,不必分配刚刚被ObjectInputStream实现使用的私有数据。 |
|
**ObjectInputStream(InputStream in) ** 创建从指定的InputStream读取的ObjectInputStream。 |
举例
类:
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
主函数(将对象反序列化):
public class Demo08 {
public static void main(String[] args) throws Exception{
FileInputStream fis=new FileInputStream("D:\\stu.bin");
ObjectInputStream ois=new ObjectInputStream(fis);
//反序列化(读取文件)
//只能读一次,不能读多次
Student s=(Student)ois.readObject();
//关闭
ois.close();
//输出
System.out.println("姓名:"+s.getName());
System.out.println("年龄:"+s.getAge());
}
}
//输出:
姓名:张三
年龄:18
序列化和反序列化注意事项
-
序列化类必须要实现Serializable接口
-
序列化类中对象属性要求实现Serializable接口
例:
要将Student类序列化,但其中的属性有Person类型,就要把Person类也实现Serializable接口
public class Student implements Serializable { private Person s1;//对象属性 private int a; } -
被序列化的类中可以写上serialVersionUID也就是序列化版本号ID,保证序列化的类和反序列化的类是同一个类
如果序列化和反序列化的类序列化版本号ID不同的话会出错
例:
private static final long serialVersionUID=100L; -
使用transient修饰属性,这个属性不能序列化(只是这个属性不能序列化)
transient代表瞬时的
-
静态属性(static)不能被序列化
-
序列化多个对象时
- 则可以反序列化多个对象(举例1)
- 可以借助集合实现(举例2)
例如:序列化s1和s2(第一次序列化s1第二次序列化s2),则通过反序列化两次可以取得所有值
例1:
序列化:
public class Demo07 { public static void main(String[] args) throws Exception{ FileOutputStream fos=new FileOutputStream("D:\\stu.bin");//bin表示二进制文件 ObjectOutputStream oos=new ObjectOutputStream(fos); //序列化 Student zhangsan=new Student("张三",18); Student lisi=new Student("李四",19); oos.writeObject(zhangsan); oos.writeObject(lisi); //关闭 oos.close(); System.out.println("序列化完毕"); } }反序列化:
public class Demo08 { public static void main(String[] args) throws Exception{ FileInputStream fis=new FileInputStream("D:\\stu.bin"); ObjectInputStream ois=new ObjectInputStream(fis); //反序列化(读取文件) //序列化了两次,所以可以反序列化两次 Student s=(Student)ois.readObject(); Student s1=(Student)ois.readObject(); //关闭 ois.close(); //输出 System.out.println("姓名:"+s.getName()); System.out.println("年龄:"+s.getAge()); System.out.println("姓名:"+s1.getName()); System.out.println("年龄:"+s1.getAge()); } } //输出: 姓名:张三 年龄:18 姓名:李四 年龄:19例2:
序列化:
public class Demo07 { public static void main(String[] args) throws Exception{ FileOutputStream fos=new FileOutputStream("D:\\stu.bin");//bin表示二进制文件 ObjectOutputStream oos=new ObjectOutputStream(fos); //序列化 Student zhangsan=new Student("张三",18); Student lisi=new Student("李四",19); ArrayList<Student> a=new ArrayList<>(); a.add(zhangsan); a.add(lisi); oos.writeObject(zhangsan); oos.writeObject(lisi); oos.writeObject(a); //关闭 oos.close(); System.out.println("序列化完毕"); } }反序列化:
public class Demo08 { public static void main(String[] args) throws Exception{ FileInputStream fis=new FileInputStream("D:\\stu.bin"); ObjectInputStream ois=new ObjectInputStream(fis); //反序列化(读取文件) //序列化了三次,所以可以反序列化三次 Student s=(Student)ois.readObject(); Student s1=(Student)ois.readObject(); ArrayList<Student> s2=(ArrayList<Student>) ois.readObject(); //关闭 ois.close(); //输出 System.out.println("姓名:"+s.getName()); System.out.println("年龄:"+s.getAge()); System.out.println("姓名:"+s1.getName()); System.out.println("年龄:"+s1.getAge()); System.out.println(s2.toString()); } } //输出: 姓名:张三 年龄:18 姓名:李四 年龄:19 [[张三 18], [李四 19]]

浙公网安备 33010602011771号