GVKun编程网logo

在Java中将对象的临时成员反序列化为非null的默认值(java临时对象定义)

32

在本文中,我们将给您介绍关于在Java中将对象的临时成员反序列化为非null的默认值的详细内容,并且为您解答java临时对象定义的相关问题,此外,我们还将为您提供关于Java基础学习总结——Java对

在本文中,我们将给您介绍关于在Java中将对象的临时成员反序列化为非null的默认值的详细内容,并且为您解答java临时对象定义的相关问题,此外,我们还将为您提供关于Java 基础学习总结 ——Java 对象的序列化和反序列化、Java 对象的序列化、反序列化、Java 对象的序列化和反序列化、Java 对象的序列化和反序列化实践的知识。

本文目录一览:

在Java中将对象的临时成员反序列化为非null的默认值(java临时对象定义)

在Java中将对象的临时成员反序列化为非null的默认值(java临时对象定义)

public class MyObj implements Serializable {  private transient Map<String, Object> myHash = new HashMap<String, Object>();  ...}

有什么方法可以确保当对上述类的对象进行反序列化时,成员myHash将被设置为新的空Map,而不是被设置为null?

答案1

小编典典
public class MyObj implements Serializable {    private transient Map<String, Object> myHash = new HashMap<String, Object>();    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {        in.defaultReadObject();        myHash = new HashMap<String, Object>();    }}

Java 基础学习总结 ——Java 对象的序列化和反序列化

Java 基础学习总结 ——Java 对象的序列化和反序列化

Java 基础学习总结 ——Java 对象的序列化和反序列化

一、序列化和反序列化的概念

  把对象转换为字节序列的过程称为对象的序列化
  把字节序列恢复为对象的过程称为对象的反序列化
  对象的序列化主要有两种用途:
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

  在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是 Web 服务器中的 Session 对象,当有 10 万用户并发访问,就有可能出现 10 万个 Session 对象,内存可能吃不消,于是 Web 容器就会把一些 seesion 先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

  当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个 Java 对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为 Java 对象。

二、JDK 类库中的序列化 API

  java.io.ObjectOutputStream 代表对象输出流,它的 writeObject (Object obj) 方法可对参数指定的 obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。
  java.io.ObjectInputStream 代表对象输入流,它的 readObject () 方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
  只有实现了 Serializable 和 Externalizable 接口的类的对象才能被序列化。Externalizable 接口继承自 Serializable 接口,实现 Externalizable 接口的类完全由自身来控制序列化的行为,而仅实现 Serializable 接口的类可以 采用默认的序列化方式 。
  对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
  2) 通过对象输出流的 writeObject () 方法写对象。

  对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
  2) 通过对象输入流的 readObject () 方法读取对象。

对象序列化和反序列范例:

  定义一个 Person 类,实现 Serializable 接口

复制代码

1 import java.io.Serializable;
 2 
 3 /**
 4  * <p>ClassName: Person<p>
 5  * <p>Description:测试对象序列化和反序列化<p>
 6  * @author xudp
 7  * @version 1.0 V
 8  * @createTime 2014-6-9 下午02:33:25
 9  */
10 public class Person implements Serializable {
11 
12     /**
13      * 序列化ID
14      */
15     private static final long serialVersionUID = -5809782578272943999L;
16     private int age;
17     private String name;
18     private String sex;
19 
20     public int getAge() {
21         return age;
22     }
23 
24     public String getName() {
25         return name;
26     }
27 
28     public String getSex() {
29         return sex;
30     }
31 
32     public void setAge(int age) {
33         this.age = age;
34     }
35 
36     public void setName(String name) {
37         this.name = name;
38     }
39 
40     public void setSex(String sex) {
41         this.sex = sex;
42     }
43 }

复制代码

  序列化和反序列化 Person 类对象

复制代码

1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileNotFoundException;
 4 import java.io.FileOutputStream;
 5 import java.io.IOException;
 6 import java.io.ObjectInputStream;
 7 import java.io.ObjectOutputStream;
 8 import java.text.MessageFormat;
 9 
10 /**
11  * <p>ClassName: TestObjSerializeAndDeserialize<p>
12  * <p>Description: 测试对象的序列化和反序列<p>
13  * @author xudp
14  * @version 1.0 V
15  * @createTime 2014-6-9 下午03:17:25
16  */
17 public class TestObjSerializeAndDeserialize {
18 
19     public static void main(String[] args) throws Exception {
20         SerializePerson();//序列化Person对象
21         Person p = DeserializePerson();//反序列Perons对象
22         System.out.println(MessageFormat.format("name={0},age={1},sex={2}",
23                                                  p.getName(), p.getAge(), p.getSex()));
24     }
25     
26     /**
27      * MethodName: SerializePerson 
28      * Description: 序列化Person对象
29      * @author xudp
30      * @throws FileNotFoundException
31      * @throws IOException
32      */
33     private static void SerializePerson() throws FileNotFoundException,
34             IOException {
35         Person person = new Person();
36         person.setName("gacl");
37         person.setAge(25);
38         person.setSex("男");
39         // ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
40         ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
41                 new File("E:/Person.txt")));
42         oo.writeObject(person);
43         System.out.println("Person对象序列化成功!");
44         oo.close();
45     }
46 
47     /**
48      * MethodName: DeserializePerson 
49      * Description: 反序列Perons对象
50      * @author xudp
51      * @return
52      * @throws Exception
53      * @throws IOException
54      */
55     private static Person DeserializePerson() throws Exception, IOException {
56         ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
57                 new File("E:/Person.txt")));
58         Person person = (Person) ois.readObject();
59         System.out.println("Person对象反序列化成功!");
60         return person;
61     }
62 
63 }

复制代码

代码运行结果如下:

序列化 Person 成功后在 E 盘生成了一个 Person.txt 文件,而反序列化 Person 是读取 E 盘的 Person.txt 后生成了一个 Person 对象

 三、serialVersionUID 的作用

  s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​:​ ​字​面​意​思​上​是​序​列​化​的​版​本​号​,凡是实现 Serializable 接口的类都有一个表示序列化版本标识符的静态变量

1 private static final long serialVersionUID

  实现 Serializable 接口的类如果类中没有添加 serialVersionUID,那么就会出现如下的警告提示

  

  用鼠标点击就会弹出生成 serialVersionUID 的对话框,如下图所示:

  

  serialVersionUID 有两种生成方式:

  采用这种方式生成的 serialVersionUID 是 1L,例如:

1 private static final long serialVersionUID = 1L;

  采用这种方式生成的 serialVersionUID 是根据类名,接口名,方法和属性等来生成的,例如:

1 private static final long serialVersionUID = 4603642343377807741L;

  添加了之后就不会出现那个警告提示了,如下所示:

  

  扯了那么多,那么 serialVersionUID (序列化版本号) 到底有什么用呢,我们用如下的例子来说明一下 serialVersionUID 的作用,看下面的代码:

复制代码

1 import java.io.File;
 2 import java.io.FileInputStream;
 3 import java.io.FileNotFoundException;
 4 import java.io.FileOutputStream;
 5 import java.io.IOException;
 6 import java.io.ObjectInputStream;
 7 import java.io.ObjectOutputStream;
 8 import java.io.Serializable;
 9 
10 public class TestSerialversionUID {
11 
12     public static void main(String[] args) throws Exception {
13         SerializeCustomer();// 序列化Customer对象
14         Customer customer = DeserializeCustomer();// 反序列Customer对象
15         System.out.println(customer);
16     }
17 
18     /**
19      * MethodName: SerializeCustomer 
20      * Description: 序列化Customer对象
21      * @author xudp
22      * @throws FileNotFoundException
23      * @throws IOException
24      */
25     private static void SerializeCustomer() throws FileNotFoundException,
26             IOException {
27         Customer customer = new Customer("gacl",25);
28         // ObjectOutputStream 对象输出流
29         ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
30                 new File("E:/Customer.txt")));
31         oo.writeObject(customer);
32         System.out.println("Customer对象序列化成功!");
33         oo.close();
34     }
35 
36     /**
37      * MethodName: DeserializeCustomer 
38      * Description: 反序列Customer对象
39      * @author xudp
40      * @return
41      * @throws Exception
42      * @throws IOException
43      */
44     private static Customer DeserializeCustomer() throws Exception, IOException {
45         ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
46                 new File("E:/Customer.txt")));
47         Customer customer = (Customer) ois.readObject();
48         System.out.println("Customer对象反序列化成功!");
49         return customer;
50     }
51 }
52 
53 /**
54  * <p>ClassName: Customer<p>
55  * <p>Description: Customer实现了Serializable接口,可以被序列化<p>
56  * @author xudp
57  * @version 1.0 V
58  * @createTime 2014-6-9 下午04:20:17
59  */
60 class Customer implements Serializable {
61     //Customer类中没有定义serialVersionUID
62     private String name;
63     private int age;
64 
65     public Customer(String name, int age) {
66         this.name = name;
67         this.age = age;
68     }
69 
70     /*
71      * @MethodName toString
72      * @Description 重写Object类的toString()方法
73      * @author xudp
74      * @return string
75      * @see java.lang.Object#toString()
76      */
77     @Override
78     public String toString() {
79         return "name=" + name + ", age=" + age;
80     }
81 }

复制代码

运行结果:

序列化和反序列化都成功了。

下面我们修改一下 Customer 类,添加多一个 sex 属性,如下:

复制代码

1 class Customer implements Serializable {
 2     //Customer类中没有定义serialVersionUID
 3     private String name;
 4     private int age;
 5 
 6     //新添加的sex属性
 7     private String sex;
 8     
 9     public Customer(String name, int age) {
10         this.name = name;
11         this.age = age;
12     }
13     
14     public Customer(String name, int age,String sex) {
15         this.name = name;
16         this.age = age;
17         this.sex = sex;
18     }
19 
20     /*
21      * @MethodName toString
22      * @Description 重写Object类的toString()方法
23      * @author xudp
24      * @return string
25      * @see java.lang.Object#toString()
26      */
27     @Override
28     public String toString() {
29         return "name=" + name + ", age=" + age;
30     }
31 }

复制代码

  然后执行反序列操作,此时就会抛出如下的异常信息:

1 Exception in thread "main" java.io.InvalidClassException: Customer; 
2 local class incompatible: 
3 stream classdesc serialVersionUID = -88175599799432325, 
4 local class serialVersionUID = -5182532647273106745

  意思就是说,文件流中的 class 和 classpath 中的 class,也就是修改过后的 class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定 serialVersionUID。在 TestSerialversionUID 例子中,没有指定 Customer 类的 serialVersionUID 的,那么 java 编译器会自动给这个 class 进行一个摘要算法,类似于指纹算法,只要这个文件 多一个空格,得到的 UID 就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,添加了一个字段后,由于没有显指定 serialVersionUID,编译器又为我们生成了一个 UID,当然和前面保存在文件中的那个不会一样了,于是就出现了 2 个序列化版本号不一致的错误。因此,只要我们自己指定了 serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。

  下面继续修改 Customer 类,给 Customer 指定一个 serialVersionUID,修改后的代码如下:

复制代码

1 class Customer implements Serializable {
 2     /**
 3      * Customer类中定义的serialVersionUID(序列化版本号)
 4      */
 5     private static final long serialVersionUID = -5182532647273106745L;
 6     private String name;
 7     private int age;
 8 
 9     //新添加的sex属性
10     //private String sex;
11     
12     public Customer(String name, int age) {
13         this.name = name;
14         this.age = age;
15     }
16     
17     /*public Customer(String name, int age,String sex) {
18         this.name = name;
19         this.age = age;
20         this.sex = sex;
21     }*/
22 
23     /*
24      * @MethodName toString
25      * @Description 重写Object类的toString()方法
26      * @author xudp
27      * @return string
28      * @see java.lang.Object#toString()
29      */
30     @Override
31     public String toString() {
32         return "name=" + name + ", age=" + age;
33     }
34 }

复制代码

  重新执行序列化操作,将 Customer 对象序列化到本地硬盘的 Customer.txt 文件存储,然后修改 Customer 类,添加 sex 属性,修改后的 Customer 类代码如下:

复制代码

1 class Customer implements Serializable {
 2     /**
 3      * Customer类中定义的serialVersionUID(序列化版本号)
 4      */
 5     private static final long serialVersionUID = -5182532647273106745L;
 6     private String name;
 7     private int age;
 8 
 9     //新添加的sex属性
10     private String sex;
11     
12     public Customer(String name, int age) {
13         this.name = name;
14         this.age = age;
15     }
16     
17     public Customer(String name, int age,String sex) {
18         this.name = name;
19         this.age = age;
20         this.sex = sex;
21     }
22 
23     /*
24      * @MethodName toString
25      * @Description 重写Object类的toString()方法
26      * @author xudp
27      * @return string
28      * @see java.lang.Object#toString()
29      */
30     @Override
31     public String toString() {
32         return "name=" + name + ", age=" + age;
33     }
34 }

复制代码

执行反序列操作,这次就可以反序列成功了,如下所示:

  

四、serialVersionUID 的取值

  serialVersionUID 的取值是 Java 运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的 serialVersionUID 的取值有可能也会发生变化。
  类的 serialVersionUID 的默认值完全依赖于 Java 编译器的实现,对于同一个类,用不同的 Java 编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高 serialVersionUID 的独立性和确定性,强烈建议在一个可序列化类中显示的定义 serialVersionUID,为它赋予明确的值

  显式地定义 serialVersionUID 有两种用途:
    1、 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的 serialVersionUID;
    2、 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的 serialVersionUID。

转发地址:https://www.cnblogs.com/xdp-gacl/p/3777987.html

Java 对象的序列化、反序列化

Java 对象的序列化、反序列化

 

对象的序列化(Serialize):将内存中的Java对象转换为与平台无关的二进制流(字节序列),然后存储在磁盘文件中,或通过网络传输给另一个网络节点。

对象的反序列化(Deserialize):获取序列化的二进制流(不管是通过网络,还是通过读取磁盘文件),将之恢复为原来的Java对象。

 

 

要实现对象的序列化,该对象所属的类必须要是可序列化的,即该类必须实现以下2个接口之一:

  • Serializable     这只是一个标记接口,此接口只是表明该类是可序列化的,不用实现任何方法。Java自带的类基本都已implement  Serializable,不用我们操心,我们自定义的类                         要实现序列化,必须要手写implement  Serializable。
  • Externalizable      用于实现自定义序列化

 

要通过网络传输的Java对象、要保存到磁盘的Java对象必须要是可序列化的,不然程序会出现异常。

JavaEE的分布式应用往往要跨平台、跨网络,通过网络传输的Java对象必须要是可序列化的,HttpSession、ServletContext等Java  Web对象都已实现序列化。如果我们要通过网络传输自定义的Java对象,该类(一般是JavaBean)要是可序列化的。通常建议:把所有的JavaBean都写成是可序列化的。

 

 

ObjectOutputStream是一个处理流,提供了void  writeObject(Object  obj)方法用于对象的序列化(对象输出流,输出到文件/网络)。

ObjectInputStream也是一个处理流,提供了Object  readObject()方法用于反序列化(对象输入流,读取文件/网络中的对象到内存)。

 

 

示例:

 1 //要实现Serializable接口(并不用实现任何方法)
 2 class Student implements Serializable{
 3     private int id;
 4     private String name;
 5     private int age;
 6 
 7     public Student(int id,String name,int age){
 8         this.id=id;
 9         this.name=name;
10         this.age=age;
11     }
12 
13    public int getId(){
14         return this.id;
15    }
16 
17    public void setId(int id){
18         this.id=id;
19    }
20 
21    public String getName(){
22         return this.name;
23    }
24 
25    public void setName(String name){
26         this.name=name;
27    }
28 
29    public int getAge(){
30         return this.age;
31    }
32 
33    public void setAge(int age){
34         this.age=age;
35    }

 

 1  //序列化
 2         ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("./obj.txt"));  //处理流,要建立在节点流之上
 3         Student zhangsan=new Student(1,"张三",20);
 4         oos.writeObject(zhangsan);   //writeObject(Object obj)用于序列化一个对象(输出到文件/网络节点)
 5 
 6         //反序列化
 7         ObjectInputStream ois=new ObjectInputStream(new FileInputStream("./obj.txt"));
 8         Student student=(Student)ois.readObject();   //返回的是Object类型,所以往往要强制类型转换
 9 
10         System.out.println("学号:"+student.getId());
11         System.out.println("姓名:"+student.getName());
12         System.out.println("年龄:"+student.getAge());

 

ObjectInputStream、ObjectOutputStream也包含了其他IO方法,可输入/输出多种类型的数据,即可以字符为单位进行操作,又可以字节为单位进行操作。

 

 

writeObject(Object  obj)一次只能写出一个对象,可多次调用,向同一文件中写入多个对象;

readObject()一次只能读一个对象,读取一个对象后,指针自动后移,指向下一个对象。读的顺序和写的顺序是一一对应的。

示例:

 1  //序列化,向同一文件中写入多个对象
 2         ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("./obj.txt"));  //处理流,要建立在节点流之上
 3         Student zhangsan=new Student(1,"张三",20);
 4         Student lisi=new Student(2,"李四",20);
 5         Student wangwu=new Student(3,"王五",20);
 6         oos.writeObject(zhangsan);  //张三
 7         oos.writeObject(lisi);  //李四
 8         oos.writeObject(wangwu);  //王五
 9 
10         //反序列化,读取顺序和写入顺序是一致的
11         ObjectInputStream ois=new ObjectInputStream(new FileInputStream("./obj.txt"));
12         Student zhangsan1=(Student)ois.readObject();    //张三
13         Student lisi1=(Student)ois.readObject();  //李四
14         Student wangwu1=(Student)ois.readObject();  //王五

 

 

 

 

如果要序列化的类有父类(直接或者间接),那么这些父类必须要是可序列化的,或者具有无参的构造函数,否则会抛出 InvalidClassException  异常。

1 class Student extends People implements Serializable{
2     //......
3 }

如果Student要序列化,则有2种方案可选:

  • 其父类People也要是可序列化的(递归)。       这样Student继承自People中的成员才可以序列化输出到文件/网络。
  • 其父类不是可序列化的,但是其父类有无参的构造函数。      这样不会报错,但Student继承自People中的成员不会序列化输出到文件/网络。

 

 

 

 

如果该类持有其它类的引用,则引用的类都要是可序列化的,此类才是可序列化的。

1 class Student implements Serializable {
2     private int id;
3     private String name;  //Java自带的类基本都实现了可序列化,不用管
4     private int age;
5     private Teacher teacher;    //此类持有一个Teacher类的引用。Teacher类必须要是可序列化的,Student类才是可序列化的。
6     //......
7 }

 

 

 

 

 

如果要多次输出同一个对象,则第一次输出的是该对象的字节序列,以后每次输出的是该对象的编号。

1   ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("./obj.txt"));
2         Student zhangsan=new Student(1,"张三",20);
3 
4         oos.writeObject(zhangsan);   //第一次序列化这个对象,输出此对象的字节序列。假设此对象的编号为1,编号唯一标识此对象。
5         oos.writeObject(zhangsan);  //再次输出此对象,输出的是此对象的编号,直接输出1。读取此对象时读取的仍是zhangsan这个对象。
6         oos.writeObject(zhangsan);  //直接输出1。
7         //类似于c++中的指针,通过编号指向某个已存在对象。减少了重新序列化对象的时间、内存开销。

 

如果中间修改了此对象,再次序列化此对象时,修改后的结果不会同步到文件/网络节点中。

 1  ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("./obj.txt"));
 2         Student zhangsan=new Student(1,"张三",20);
 3 
 4         oos.writeObject(zhangsan);   //初次序列化,输出此对象的字节序列。假设编号为1
 5         zhangsan.setName("李四");   //之后修改了此对象
 6         oos.writeObject(zhangsan);  //再次输出此对象,输出的是编号1。1代表编号为1的对象。
 7 
 8         /*
 9         在此对象第一次序列化之后,对此对象做修改,后面再次输出此对象时,都是指向第一次输出的那个对象,做的修改并不会写到文件/网络节点中。
10         读取的也都是第一次输出的那个对象。
11 
12         实际上,序列化一个对象时,JVM会先检查在本次虚拟机中是否已序列化过这个对象,如果已序列化过,直接输出对应的序列化编号,未序列化过才序列化。
13      JVM是以对象名来区分序列化的是否是同一个对象。对象名相同,JVM就认为序列化的是同一个对象,直接输出该对象的编号,并不判断此对象是否修改过。
14

15 修改此对象后,就算我们把此对象序列化到另一个文件中,输出的也是此对象第一次序列化时的编号,修改并不会同步到这个文件中。
16 */

 

 

 

 

 

Java9新增了过滤功能,读取对象时,可以先检查该对象是否满足指定的要求,满足才允许恢复,否则拒绝恢复。

 1  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("obj.txt"));
 2         /*
 3         参数是一个ObjectInputFilter接口的对象,函数式接口,只需实现checkInput()方法。
 4         参数info是FilterInfo类的对象。
 5 
 6         返回值要是预定义的常量:
 7         Status.ALLOWED  允许恢复
 8         Status.REJECTED  拒绝恢复
 9         Status.UNDECIDED  未决定,将继续执行检查
10          */
11         ois.setObjectInputFilter((info)->{
12             ObjectInputFilter serialFilter=ObjectInputFilter.Config.getSerialFilter();   //获取默认的输入过滤器
13             if(serialFilter!=null){
14                 //先使用默认的过滤器进行检查
15                 ObjectInputFilter.Status status=serialFilter.checkInput(info);
16                 //如果已知道结果
17                 if (status!= ObjectInputFilter.Status.UNDECIDED)
18                     return status;
19             }
20             //执行到此,就说明结果是Status.UNDECIDED,还不知道结果,要继续检查
21             //如果引用不唯一,说明数据被污染了,不允许恢复
22             if(info.references()!=1)
23                 return ObjectInputFilter.Status.REJECTED;
24             //是指定的类的对象(Student),才允许恢复(执行反序列化)
25             if(info.serialClass()!=null && info.serialClass() != Student.class)
26                 return ObjectInputFilter.Status.ALLOWED;
27             //执行到此,说明不是指定类的对象,不允许恢复。
28             return ObjectInputFilter.Status.REJECTED;
29         });
30         //这样恢复的对象都是唯一的Student对象
31         //...........

 

Java 对象的序列化和反序列化

Java 对象的序列化和反序列化

一。序列化和反序列化的概念

      把对象转换为字节序列的过程称为对象的序列化。

      把字节序列恢复为对象的过程称为对象的反序列化。

      对象的序列化主要有两种用途:

      1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

      2) 在网络上传送对象的字节序列。

      在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是 Web 服务器中的 Session 对象,当有 10 万用户并发访问,就有可能出现 10 万个 Session 对象,内存可能吃不消,于是 Web 容器就会把一些 seesion 先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

      当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个 Java 对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为 Java 对象。


二.JDK 库类中的序列化 API

      java.io.ObjectOutputStream 代表对象输出流,它的 writeObject (Object obj) 方法可对参数指定的 obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。

      java.io.ObjectInputStream 代表对象输入流,它的 readObject () 方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

     只有实现了 Serializable 和 Externalizable 接口的类的对象才能被序列化。Externalizable 接口继承自 Serializable 接口,实现 Externalizable 接口的类完全由自身来控制序列化的行为,而仅实现 Serializable 接口的类可以 采用默认的序列化方式 。

      对象序列化包括如下步骤

      1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;

      2) 通过对象输出流的 writeObject() 方法写对象。

      对象反序列化步骤如下:

      1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;  

      2) 通过对象输入流的 readObject() 方法读取对象。


三。对象序列化和反序列化案例

      定义一个 Person 类,实现 Serializable 接口

import java.io.Serializable;
/**
 * 测试对象序列化和反序列化
 * @author 
 * @version 1.0 V
 * @createTime 
 */
public class Person implements Serializable {
    /**
     * 序列化ID
     */
    private static final long serialVersionUID = -5809782578272943999L;
    private int age;
    private String name;
    private String sex;
    public int getAge() {
        return age;
    }
    public String getName() {
        return name;
    }
    public String getSex() {
        return sex;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}

      序列化和反序列化 Person 类对象

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.MessageFormat;
/**
 * 测试对象的序列化和反序列
 * @author 
 * @version 1.0 V
 * @createTime 
 */
public class TestObjSerializeAndDeserialize {
    public static void main(String[] args) throws Exception {
        SerializePerson();//序列化Person对象
        Person p = DeserializePerson();//反序列Perons对象
        System.out.println(MessageFormat.format("name={0},age={1},sex={2}",
                                                 p.getName(), p.getAge(), p.getSex()));
    }
    
    /**
     * MethodName: SerializePerson 
     * Description: 序列化Person对象
     * @author 
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void SerializePerson() throws FileNotFoundException,
            IOException {
        Person person = new Person();
        person.setName("gacl");
        person.setAge(25);
        person.setSex("男");
        // ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
                new File("E:/Person.txt")));
        oo.writeObject(person);
        System.out.println("Person对象序列化成功!");
        oo.close();
    }
    /**
     * MethodName: DeserializePerson 
     * Description: 反序列Perons对象
     * @author 
     * @return
     * @throws Exception
     * @throws IOException
     */
    private static Person DeserializePerson() throws Exception, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                new File("E:/Person.txt")));
        Person person = (Person) ois.readObject();
        System.out.println("Person对象反序列化成功!");
        return person;
    }
}



四.serialVersionUID 的作用

稍后补充~

Java 对象的序列化和反序列化实践

Java 对象的序列化和反序列化实践


当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个 Java 对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为 Java 对象。

  把 Java 对象转换为字节序列的过程称为对象的序列化。

  把字节序列恢复为 Java 对象的过程称为对象的反序列化。

  对象的序列化主要有两种用途:

  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;

  2) 在网络上传送对象的字节序列。

一. JDK 类库中的序列化 API

  java.io.ObjectOutputStream 代表对象输出流,它的 writeObject (Object obj) 方法可对参数指定的 obj 对象进行序列化,把得到的字节序列写到一个目标输出流中。

  java.io.ObjectInputStream 代表对象输入流,它的 readObje

我们今天的关于在Java中将对象的临时成员反序列化为非null的默认值java临时对象定义的分享就到这里,谢谢您的阅读,如果想了解更多关于Java 基础学习总结 ——Java 对象的序列化和反序列化、Java 对象的序列化、反序列化、Java 对象的序列化和反序列化、Java 对象的序列化和反序列化实践的相关信息,可以在本站进行搜索。

本文标签: