序列化与transient关键字
序列化与反序列化
序列化: 将数据结构或对象转换成二进制串的过程
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
Serializable接口
public interface Serializable {
}
(1)Serializable接口是一个空接口,如果一个类实现了 Serializable接口,该类就自动实现了序列化和反序列化
(2)Java的Serializable,只能序列化类的状态,不能序列化类的方法
(3)如果一个类实现了Serializable接口,其父类没有实现Serializable接口,那么父类必须有无参的构造器,并且父类中的状态默认不能被序列化
ObjectOutputStream和ObjectInputStream
@Data
@AllArgsConstructor
public class Person implements Serializable {
private String name;
private Integer age;
private String phone;
}
Person对象不实现Serializable接口,不能将对象转换成二进制数据写入文件中
@Test
void contextLoads() throws Exception {
String path = "F:/demo/person.dat";
Person person = new Person("小明", 12, "1111");
// 序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
objectOutputStream.writeObject(person);
objectOutputStream.close();
// 反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));
Person person1 = (Person) objectInputStream.readObject();
objectInputStream.close();
System.out.println("反序列化:" + person1);
System.out.println(person == person1);
}
打印出来的结果是:
反序列化:Person(name=小明, age=12, phone=1111)
false
反序列化回来得到的Person对象p2和之前的p1内地地址不一样,是深拷贝。
使用transient关键字干预序列化
@Data
@AllArgsConstructor
public class Person implements Serializable {
private transient String name;
private Integer age;
private String phone;
}
反序列化:Person(name=null, age=12, phone=1111)
false
1)一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口
注:
成员变量:new 对象时开始,未被引用时结束
本地变量:方法参数或方法内局部变量,运行至代码处创建
类变量:被static修饰的变量,类加载时创建
3)被transient修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化
@Component
public class ExternalizableTest implements Externalizable {
public transient String content = "aaa";
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(content);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
content = (String) in.readObject();
}
}
@Test
public void testExternalizable() throws Exception {
String path = "F:/demo/person.dat";
// 序列化
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
objectOutputStream.writeObject(externalizableTest);
objectOutputStream.close();
// 反序列化
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));
ExternalizableTest test = (ExternalizableTest) objectInputStream.readObject();
objectInputStream.close();
System.out.println(test.content);
}
aaa
对象的序列化可以通过实现两种接口来实现,若实现的是Serializable接口,则所有的序列化将会自动进行,若实现的是Externalizable接口,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Externalizable {
private transient String name;
private Integer age;
private String phone;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
}
反序列化:Person(name=null, age=null, phone=null)
false