Java提供了一种对象序列化的机制:
用一个字节序列可以表示一个对象 该字节序列包含该对象的数据 类型 和 对象中存储的属性等信息
字节序列写出到文件之后 相当于文件中持久保存了一个对象的信息
反之 该字节序列还可以从文件中读取回来 重构对象 对它进行反序列化
对象的数据 对象的类型和对象中存储的数据信息 都可以用来在内存中创建对象
例:Person p=new Person("陈涛",18)
一、ObjectOutputStream 对象序列化流
ObjectOutputStream类将Java对象的原始数据类型写出到文件 实现对象的持久存储
java.io.ObjectOutputStream对象序列化流继承了OutputStream
将对象以流的方式写入到文件中保存
构造方法:
public ObjectOutputStream(OutputStream out):创建一个指定OutputStream的ObjectOutputStream
参数:OutputStream out 字节输出流
特有的成员方法:
writeObject(Object obj):将指定的对象写入ObjectOutputStream
使用步骤:
1、创建ObjectOutputStream对象 构造方法中传递字节输出流
2、使用ObjectOutputStream对象对象中的writeObject()方法 将对象写入到文件中
3、释放资源
慢着!怎么出现了这个异常 咋回事啊
NotSerializableException异常处理:
Exception in thread “main” java.io.NotSerializableException: objectStream.Person

java.io.Serializable接口:未实现此接口的类将无法使其任何状态序列化或反序列化
Serializable 是一个标记接口 里面没有任何方法 仅仅起到一个标记的作用
不实现此接口的类将不会使任何状态序列化或反序列化 会抛出NotSerializableException
当进行序列化和反序列化操作的时候 会检测类上是否有这个标记
若有:可以序列化和反序列化
若没有:抛出NotSerializableException异常
public class Person implements Serializable {
private String name;
private int age;
...
}
public static void main(String[] args) throws IOException {
// 创建ObjectOutputStream对象 构造方法中传递字节输出流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("F:\\IdeaProjects\\filetest\\person.txt"));
// 使用ObjectOutputStream对象对象中的writeObject()方法 将对象写入到文件中
oos.writeObject(new Person("陈涛",18));
// 释放资源
oos.close();
}
二、ObjecInputStream 对象反序列化流
ObjectInputStream反序列化流 可将之前使用ObjectOutputStream序列化的原始数据恢复为对象
构造方法:
public ObjectInputStream(InputStream in):创建一个指定InputStream的ObjectInputStream
参数:
InputStream in 字节输入流
特有的成员方法:
Object readObject():从ObjectInputStream读取对象
readObject()方法会抛出ClassNotFoundException异常(Class文件找不到异常)
当不存在对象的class文件时 会抛出此异常
因此 反序列化的前提:
1、该类必须实现java.io.Serializable接口
2、必须存在该类对应的class文件
使用步骤:
1、创建ObjectInputStream对象 构造方法中传递字节输入流
2、使用ObjectInputStream对象中的readObject()方法 读取保存对象的文件
3、释放资源
4、使用读取出的对象
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 创建ObjectInputStream对象 构造方法中传递字节输入流
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("F:\\IdeaProjects\\filetest\\person.txt"));
// 使用ObjectInputStream对象中的readObject()方法 读取保存对象的文件
Object object = ois.readObject();
// 释放资源
ois.close();
// 使用读取出的对象
System.out.println(object);
System.out.println(((Person)object).getName()+((Person)object).getAge());
}
transient 瞬态关键字
static关键字:静态关键字
优先于非静态加载到内存中 因此 被static修饰的成员变量是不能被序列化的
因为只能对对象进行序列化操作 而被静态关键字修饰后不属于对象
transient关键字:瞬态关键字
当读取的属性为静态属性时 序列化后会无法正常反序列化 会读取不到数据 使用该属性的默认值
被transient修饰的成员变量不能被序列化 只是没有静态的功能 仅仅只是不能被序列化而已
例:private transient int age
总结:反序列化的前提
1、该类必须实现java.io.Serializable接口
Serializable是一个标记接口 里面没有任何方法 仅仅起到一个标记的作用
不实现此接口的类将不会使任何状态序列化或反序列化 会抛出 NotSerializableException异常
2、该类的所有属性必须是可序列化的
若有一个属性不需要可序列化的 则该属性必须注明是瞬态的 使用transient关键字修饰
为啥又出现异常了?
InvalidClassException异常
当JVM反序列化对象时 若能找到class文件 但class文件在序列化对象之后发生了修改 那么反序列化操作也会失败
此时会抛出一个InvalidClassException异常
例:Exception in thread "main" java.io.InvalidClassException: objectStream.Person; local class incompatible: stream classdesc serialVersionUID = 1120242798634133694, local class serialVersionUID = 8382704104194838558
造成该异常的可能原因:
1、该类的序列版本号与从流中读取的类描述符的版本号不匹配
2、该类包含未知数据类型
3、该类没有可访问的无参数构造方法
原理:
编译器(javac)会将java文件编译成class文件
当类实现了Serializable接口 会根据类里定义的属性和方法给class文件添加一个名为serialVersionUID的序列号
当序列化保存到文本中的时候 文本中也会添加这条序列号
当进行反序列化操作的时候 会使用class文件和txt文件中的序列号进行比较
若两个序列号相匹配 则反序列化成功
若两个序列号不匹配 则抛出InvalidClassException序列化冲突异常
每次修改类的定义都会重新为class文件生成一个全新的序列号
解决方式:
可以手动给类添加一个序列号
可序列化类可以通过声明名为serialVersionUID的字段来显式声明其自己的serialVersionUID
(该字段必须为static final的long类型字段)
例:
该serialVersionUID属性的值可以任意填入
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public int age;
...
}
1万+




被折叠的 条评论
为什么被折叠?



