对象序列化有什么用
在Java中我们可以在内存中创建多个可复用的Java对象,但是这些对象只有在JVM运行时才会存在,在实际运用中我们可能会遇到在JVM停止运行后还能保存对象、在网络中传输对象等需求。这时序列化技术就可以帮助我们实现这些需求。
序列化的方式
1.实现Serializable接口
这是使用最多的一种方式,Serializable接口是一个空接口,不需要我们重写任何方法,它的主要作用就是用来标识可以序列化。
下面是一些具体的例子:
单个对象的序列化
Students类
public class Students implements Serializable {
private String Num; //学号
private String Name; //学生姓名
private int Age; //学生年龄
public Students(String Num,String Name,int Age){
this.Num=Num;
this.Name=Name;
this.Age=Age;
}
public Students(){
}
public String getNum() {
return Num;
}
public void setNum(String num) {
Num = num;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public int getAge() {
return Age;
}
public void setAge(int age) {
Age = age;
}
@Override
public String toString() {
return "Students{" +
"Num='" + Num + '\'' +
", Name='" + Name + '\'' +
", Age=" + Age +
'}';
}
}
import java.io.*;
public class Test4 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
serialization();
deserialization();
}
// 序列化
public static void serialization() throws IOException {
File file = new File("d.txt");
OutputStream os = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(new Students("10001","张三",20));
oos.close();
System.out.println("序列化成功");
}
// 反序列化
public static void deserialization() throws IOException, ClassNotFoundException {
File file = new File("d.txt");
InputStream is = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(is);
Students students = (Students) ois.readObject();
System.out.println(students);
ois.close();
System.out.println("反序列化成功");
}
}
运行后可以看到生成了一个.txt文件并输出成功
当我们需要同时保存多个对象时,我们可以把对象放进数组或者集合中,这里重点介绍集合的序列化。通过阅读我们常用的几个集合ArrayList、LinkedList、HashSet、HashMap等我们都可以看到他们都实现了Serializable接口,所有我们也可以直接进行序列化。
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
serialization();
deserialization();
}
// 序列化
public static void serialization() throws IOException {
// ArrayList
//ArrayList list = new ArrayList();
// LinkList
//LinkedList list = new LinkedList();
// HashSet
//HashSet list = new HashSet();
// HashMap
//HashMap<Integer,Students> map = new HashMap<>();
// TreeMap
TreeMap<Integer,Students> map = new TreeMap<>();
Students student1 = new Students("10001","张三",20);
Students student2 = new Students("10002","李四",21);
Students student3 = new Students("10003","王五",22);
/*
list.add(student1);
list.add(student2);
list.add(student3);
*/
map.put(1,student1);
map.put(2,student2);
map.put(3,student3);
File file = new File("a.txt");
OutputStream os = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(map);
oos.close();
System.out.println("序列化成功");
}
// 反序列化
public static void deserialization() throws IOException, ClassNotFoundException {
File file = new File("a.txt");
InputStream is = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(is);
//ArrayList<Students> list = (ArrayList<Students>) ois.readObject();
//LinkedList<Students> list = (LinkedList<Students>) ois.readObject();
//HashSet<Students> list = (HashSet<Students>) ois.readObject();
//HashMap<Integer,Students> map = (HashMap<Integer, Students>) ois.readObject();
TreeMap<Integer,Students> map = (TreeMap<Integer, Students>) ois.readObject();
/*
for (Students s : list) {
System.out.println(s.getNum()+"\t"+ s.getName()+"\t\t"+ s.getAge());
}*/
for (Integer key:map.keySet()) {
System.out.println(map.get(key));
}
ois.close();
System.out.println("反序列化成功");
}
}
经过测试,都是没有问题的
在使用这种方法来序列化时我们还使用下面的3种方法来实现部分属性序列化
(1)使用transient修饰符
(2)使用static修饰符
(3)重写writeObject和readObject方法
2.实现Externalizable接口
Externalizable接口是继承于Serializable接口,可以说是Serializable接口的一个拓展,因为在实现Externalizable接口时我们必须重写writeExternal和readExternal这两个方法,重写时我们就可以指定要序列化的属性。
例子:
还是上面的Students类,不过得重写两个方法
这里我们就不对年龄这个属性进行序列化
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(Num);
out.writeObject(Name);
//out.writeObject(Age);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
Num = (String) in.readObject();
Name = (String) in.readObject();
//Age = (int) in.readObject();
}
import java.io.*;
import java.util.ArrayList;
public class Test3 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
serialization();
deserialization();
}
public static void serialization() throws IOException {
Students student1 = new Students("10001","张三",20);
Students student2 = new Students("10002","李四",21);
Students student3 = new Students("10003","王五",22);
ArrayList list = new ArrayList();
list.add(student1);
list.add(student2);
list.add(student3);
File file = new File("c.txt");
OutputStream os = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(list);
oos.close();
}
public static void deserialization() throws IOException, ClassNotFoundException {
File file = new File("c.txt");
InputStream is = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(is);
ArrayList<Students> list = (ArrayList<Students>) ois.readObject();
for (Students s : list) {
System.out.println(s.getNum()+"\t"+ s.getName()+"\t\t"+ s.getAge());
}
}
}
两种方法进行对比,Serializable接口实现更简单,但是执行效率会比Externalizable接口低,保存时占用的空间也更大。
为了方便使用我们可以把这两个方法包装成一个类,当需要序列化时就可以直接调用。