所有分布式应用常常需要跨平台,跨网络,因此要求所有传的参数、返回值都必须实现序列化。

比如常见的Dubbo分布式平台,里面的对象实体类必须实现序列化才能在网络间传递

一、定义

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

二、用途

  对象的序列化主要有两种用途: 
   
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;(持久化对象) 
   
  2) 在网络上传送对象的字节序列。(网络传输对象)

三、实现

  实现了如下两个接口之一的类的对象才能被序列化: 
   
  1) Serializable 
   
  2) Externalizable

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

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

  注:使用writeObject() 和readObject()方法的对象必须已经被序列化

四、深入理解

一、为什么要序列化?

  Java平台允许我们在内存中创建可复用的Java对象,但只有当JVM(Java虚拟机)处于运行时,这些对象才可能存在,也就是这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存指定的对象(持久化对象),并在将来重新读取被保存的对象。Java对象序列化就实现了该功能。 
   
  网络通信时,无论是何种类型的数据,都会转成字节序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。Java对象序列化也实现了该功能。

  所以序列化机制会把内存中的Java对象转换成与平台无关的二进制流,从而永久地保存在磁盘上或是通过网络传输到另一个网络节点。

二、序列化的意义

客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要站用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。

web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。

将HttpSession对象保存到文件系统或数据库中,需要采用序列化的方式将HttpSession对象中的每个属性对象保存到文件系统或数据库中;将HttpSession对象从文件系统或数据库中装载如内存时,需要采用反序列化的方式,恢复HttpSession对象中的每个属性对象。所以存储在HttpSession对象中的每个属性对象必须实现Serializable接口

三、Session的持久化的作用

1.提高服务器内存的利用率,保证那些暂停活动的客户端在会话超时之前继续原来的会话

2,在多台web服务器协同对外提供服务的集群系统中,使用Session的持久化技术,某台服务器可以将其中发生改变的Session对象复制给其他服务器。保证了在某台服务器停止工作后可以由其他服务器来接替它与客户端的会话

3,在一个web应用程序重启时,服务器也会持久化该应用程序中所有HttpSession对象,保证客户端的会话活动仍可以继续。

Tomcat使用Session Manager 类来管理Session的持久化,他提供了两个SessionManager类

org.apache.catalina.session.StandardManager

org.apache.catalina.session.PersistentManager

StandardManager是tomcat默认使用的,在web应用程序关闭时,对内存中的所有HttpSession对象进行持久化,把他们保存到文件系统中。默认的存储文件为

<tomcat 安装目录>/work/Catalina/<主机名>/<应用程序名>/sessions.ser

PersistentManager比StandardManager更为灵活,只要某个设备提供了实现org.apache.catalina.Store接口的驱动类,PersistentManager就可以将HttpSession对象保存到该设备

四、serialVersionUID

如果serialVersionUID没有显式生成,系统就会自动生成一个。此时,如果在序列化后我们将该类作添加或减少一个字段等的操作,系统在反序列化时会重新生成一个serialVersionUID然后去和已经序列化的对象进行比较,就会报序列号版本不一致的错误。为了避免这种问题, 一般系统都会要求实现serialiable接口的类显式的生明一个serialVersionUID。 
 显式定义serialVersionUID的两种用途: 
   1、 希望类的不同版本对序列化兼容时,需要确保类的不同版本具有相同的serialVersionUID; 
   2、 不希望类的不同版本对序列化兼容时,需要确保类的不同版本具有不同的serialVersionUID。

五、序列化机制算法

  1. 所有保存到磁盘中的对象都有一个序列化编号 
   
  2. 当程序试图序列化一个对象时,程序先检查该对象是否已经被序列化过。如果从未被序列化过,系统就会将该对象转换成字节序列并输出;如果已经序列化过,将直接输出一个序列化编号。

六、示例

  要被序列化的对象对应的类的代码:

  1. public class Person implements Serializable {
  2.  
  3. private String name = null;
  4.  
  5. private Integer age = null;
  6.  
  7. public Person(){
  8. System.out.println("无参构造");
  9. }
  10. public Person(String name, Integer age) {
  11. this.name = name;
  12. this.age = age;
  13. }
  14. //getter setter方法省略...
  15. @Override
  16. public String toString() {
  17. return "[" + name + ", " + age+"]";
  18. }
  19. }

MySerilizable 是一个简单的序列化程序,它先将一个Person对象保存到文件person.txt中,然后再从该文件中读出被存储的Person对象,并打印该对象。

  1. public class MySerilizable {
  2.  
  3. public static void main(String[] args) throws Exception {
  4. File file = new File("person.txt");
  5.  
  6. //序列化持久化对象
  7. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
  8. Person person = new Person("Peter", 27);
  9. out.writeObject(person);
  10. out.close();
  11.  
  12. //反序列化,并得到对象
  13. ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
  14. Object newPerson = in.readObject(); // 没有强制转换到Person类型
  15. in.close();
  16. System.out.println(newPerson);
  17. }
  18. }

输出结果:

  1. [Peter, 27]
  • 1

结果没有打印“无参构造”,说明反序列化机制无需通过构造器来初始Java对象。 
  注: 
   
  1.) 反序列化读取的仅仅是Java对象的数据,而不是Java类,所以在反序列化时必须提供该Java对象所属类的class文件(这里是Person.class),否则会引发ClassNotFoundException异常。 
   
  2).当重新读取被保存的Person对象时,并没有调用Person的任何构造器,说明反序列化机制无须通过构造器来初始化对象。

七、选择序列化

transient

  当对某个对象进行序列化时,系统会自动将该对象的所有属性依次进行序列化,如果某个属性引用到别一个对象,则被引用的对象也会被序列化。如果被引用的对象的属性也引用了其他对象,则被引用的对象也会被序列化。 这就是递归序列化。

  有时候,我们并不希望出现递归序列化,或是某个存敏感信息(如银行密码)的属性不被序列化,我们就可通过transient关键字修饰该属性来阻止被序列化。

将上面的Person类的age属性用transient修饰:

  1. transient private Integer age = null;
  • 1

再去执行MySerilizable的结果为:

  1. [Peter, null] //返序列化时没有值,说明age字段未被序列化
  • 1

writeObject()方法与readObject()方法

  使用transient关键字阻止序列化虽然简单方便,但被它修饰的属性被完全隔离在序列化机制之外,导致了在反序列化时无法获取该属性的值,而通过在需要序列化的对象的Java类里加入writeObject()方法与readObject()方法可以控制如何序列化各属性,甚至完全不序列化某些属性(此时就transient一样)。 
   
  如果我们想要上面的Person类里的name属性在序列化后存在文件里不让别人知道具体是什么(加密),我们就可在Person类里加如下代码:

  1. //自定义序列化
  2. private void writeObject(ObjectOutputStream out) throws IOException {
  3. // out.defaultWriteObject(); // 将当前类的非静态和非瞬态字段写入此流。
  4. //如果不写,如果还有其他字段,则不会被序列化
  5.  
  6. out.writeObject(new StringBuffer(name).reverse());
  7. //将name简单加密(反转),这样别人就知道是怎么回事,当然实际应用不可能这样加密。
  8.  
  9. out.writeInt(age);
  10. }
  11.  
  12. //反序列化
  13. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  14. //in.defaultReadObject();// 从此流读取当前类的非静态和非瞬态字段。
  15. //如果不写,其他字段就不能被反序列化
  16.  
  17. name = ((StringBuffer)in.readObject()).reverse().toString(); //解密
  18.  
  19. age = in.readInt();
  20. }

详细的自定义序列化与反序列化可参见ObjectOutputStream 和ObjectInputStream 类的JDK文档。

Externalizable接口

Externalizable接口 与Serializable 接口类似,只是Externalizable接口需要强制自定义序列化。 
要序列化对象的代码:

  1. public class Teacher implements Externalizable{
  2.  
  3. private String name;
  4. private Integer age;
  5.  
  6. public Teacher(){
  7. System.out.println("无参构造");
  8. }
  9.  
  10. public Teacher(String name,Integer age){
  11. System.out.println("有参构造");
  12. this.name = name;
  13. this.age = age;
  14. }
  15.  
  16. //setter、getter方法省略
  17.  
  18. @Override
  19. public void writeExternal(ObjectOutput out) throws IOException {
  20. out.writeObject(new StringBuffer(name).reverse()); //将name简单加密
  21. //out.writeInt(age); //注掉这句后,age属性将不能被序化
  22. }
  23.  
  24. @Override
  25. public void readExternal(ObjectInput in) throws IOException,
  26. ClassNotFoundException {
  27. name = ((StringBuffer) in.readObject()).reverse().toString();
  28. //age = in.readInt();
  29. }
  30.  
  31. @Override
  32. public String toString() {
  33. return "[" + name + ", " + age+ "]";
  34. }
  35.  
  36. }
  1. //主函数代码改为:
    public class MySerilizable {
  2.  
  3. public static void main(String[] args) throws Exception {
  4. File file = new File("person.txt");
  5.  
  6. //序列化持久化对象
  7. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
  8. Teacher person = new Teacher("Peter", 27);
  9. out.writeObject(person);
  10. out.close();
  11.  
  12. //反序列化,并得到对象
  13. ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
  14. Object newPerson = in.readObject(); // 没有强制转换到Person类型
  15. in.close();
  16. System.out.println(newPerson);
  17.  
  18. }
  19. }

打印结果:

  1. 有参构造
  2. 无参构造 //与Serializable 不同的是,还调用了无参构造
  3. [Peter, null] //age未被序列化,所以未取到值

所有分布式应用常常需要跨平台,跨网络,因此要求所有传的参数、返回值都必须实现序列化。

一、定义

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

二、用途

  对象的序列化主要有两种用途: 
   
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;(持久化对象) 
   
  2) 在网络上传送对象的字节序列。(网络传输对象)

三、实现

  实现了如下两个接口之一的类的对象才能被序列化: 
   
  1) Serializable 
   
  2) Externalizable

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

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

  注:使用writeObject() 和readObject()方法的对象必须已经被序列化

四、深入理解

一、为什么要序列化?

  Java平台允许我们在内存中创建可复用的Java对象,但只有当JVM(Java虚拟机)处于运行时,这些对象才可能存在,也就是这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存指定的对象(持久化对象),并在将来重新读取被保存的对象。Java对象序列化就实现了该功能。 
   
  网络通信时,无论是何种类型的数据,都会转成字节序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。Java对象序列化也实现了该功能。

  所以序列化机制会把内存中的Java对象转换成与平台无关的二进制流,从而永久地保存在磁盘上或是通过网络传输到另一个网络节点。

二、序列化的意义

客户端访问了某个能开启会话功能的资源, web服务器就会创建一个与该客户端对应的HttpSession对象,每个HttpSession对象都要站用一定的内存空间。如果在某一时间段内访问站点的用户很多,web服务器内存中就会积累大量的HttpSession对象,消耗大量的服务器内存,即使用户已经离开或者关闭了浏览器,web服务器仍要保留与之对应的HttpSession对象,在他们超时之前,一直占用web服务器内存资源。

web服务器通常将那些暂时不活动但未超时的HttpSession对象转移到文件系统或数据库中保存,服务器要使用他们时再将他们从文件系统或数据库中装载入内存,这种技术称为Session的持久化。

将HttpSession对象保存到文件系统或数据库中,需要采用序列化的方式将HttpSession对象中的每个属性对象保存到文件系统或数据库中;将HttpSession对象从文件系统或数据库中装载如内存时,需要采用反序列化的方式,恢复HttpSession对象中的每个属性对象。所以存储在HttpSession对象中的每个属性对象必须实现Serializable接口

三、Session的持久化的作用

1.提高服务器内存的利用率,保证那些暂停活动的客户端在会话超时之前继续原来的会话

2,在多台web服务器协同对外提供服务的集群系统中,使用Session的持久化技术,某台服务器可以将其中发生改变的Session对象复制给其他服务器。保证了在某台服务器停止工作后可以由其他服务器来接替它与客户端的会话

3,在一个web应用程序重启时,服务器也会持久化该应用程序中所有HttpSession对象,保证客户端的会话活动仍可以继续。

Tomcat使用Session Manager 类来管理Session的持久化,他提供了两个SessionManager类

org.apache.catalina.session.StandardManager

  1. org.apache.catalina.session.PersistentManager
  • 1
  • 2

StandardManager是tomcat默认使用的,在web应用程序关闭时,对内存中的所有HttpSession对象进行持久化,把他们保存到文件系统中。默认的存储文件为

四、serialVersionUID

如果serialVersionUID没有显式生成,系统就会自动生成一个。此时,如果在序列化后我们将该类作添加或减少一个字段等的操作,系统在反序列化时会重新生成一个serialVersionUID然后去和已经序列化的对象进行比较,就会报序列号版本不一致的错误。为了避免这种问题, 一般系统都会要求实现serialiable接口的类显式的生明一个serialVersionUID。 
 显式定义serialVersionUID的两种用途: 
   1、 希望类的不同版本对序列化兼容时,需要确保类的不同版本具有相同的serialVersionUID; 
   2、 不希望类的不同版本对序列化兼容时,需要确保类的不同版本具有不同的serialVersionUID。

五、序列化机制算法

  1. 所有保存到磁盘中的对象都有一个序列化编号 
   
  2. 当程序试图序列化一个对象时,程序先检查该对象是否已经被序列化过。如果从未被序列化过,系统就会将该对象转换成字节序列并输出;如果已经序列化过,将直接输出一个序列化编号。

六、示例

  要被序列化的对象对应的类的代码:

  1. public class Person implements Serializable {
  2. private String name = null;
  3. private Integer age = null;
  4. public Person(){
  5. System.out.println("无参构造");
  6. }
  7. public Person(String name, Integer age) {
  8. this.name = name;
  9. this.age = age;
  10. }
  11. //getter setter方法省略...
  12. @Override
  13. public String toString() {
  14. return "[" + name + ", " + age+"]";
  15. }
  16. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

  MySerilizable 是一个简单的序列化程序,它先将一个Person对象保存到文件person.txt中,然后再从该文件中读出被存储的Person对象,并打印该对象。

  1. public class MySerilizable {
  2. public static void main(String[] args) throws Exception {
  3. File file = new File("person.txt");
  4. //序列化持久化对象
  5. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
  6. Person person = new Person("Peter", 27);
  7. out.writeObject(person);
  8. out.close();
  9. //反序列化,并得到对象
  10. ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
  11. Object newPerson = in.readObject(); // 没有强制转换到Person类型
  12. in.close();
  13. System.out.println(newPerson);
  14. }
  15. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

  输出结果:

  1. [Peter, 27]
  • 1

结果没有打印“无参构造”,说明反序列化机制无需通过构造器来初始Java对象。 
  注: 
   
  1.) 反序列化读取的仅仅是Java对象的数据,而不是Java类,所以在反序列化时必须提供该Java对象所属类的class文件(这里是Person.class),否则会引发ClassNotFoundException异常。 
   
  2).当重新读取被保存的Person对象时,并没有调用Person的任何构造器,说明反序列化机制无须通过构造器来初始化对象。

七、选择序列化

transient

  当对某个对象进行序列化时,系统会自动将该对象的所有属性依次进行序列化,如果某个属性引用到别一个对象,则被引用的对象也会被序列化。如果被引用的对象的属性也引用了其他对象,则被引用的对象也会被序列化。 这就是递归序列化。

  有时候,我们并不希望出现递归序列化,或是某个存敏感信息(如银行密码)的属性不被序列化,我们就可通过transient关键字修饰该属性来阻止被序列化。

将上面的Person类的age属性用transient修饰:

  1. transient private Integer age = null;
  • 1

再去执行MySerilizable的结果为:

  1. [Peter, null] //返序列化时没有值,说明age字段未被序列化
  • 1

writeObject()方法与readObject()方法

  使用transient关键字阻止序列化虽然简单方便,但被它修饰的属性被完全隔离在序列化机制之外,导致了在反序列化时无法获取该属性的值,而通过在需要序列化的对象的Java类里加入writeObject()方法与readObject()方法可以控制如何序列化各属性,甚至完全不序列化某些属性(此时就transient一样)。 
   
  如果我们想要上面的Person类里的name属性在序列化后存在文件里不让别人知道具体是什么(加密),我们就可在Person类里加如下代码: 
  

  1. //自定义序列化
  2. private void writeObject(ObjectOutputStream out) throws IOException {
  3. // out.defaultWriteObject(); // 将当前类的非静态和非瞬态字段写入此流。
  4. //如果不写,如果还有其他字段,则不会被序列化
  5. out.writeObject(new StringBuffer(name).reverse());
  6. //将name简单加密(反转),这样别人就知道是怎么回事,当然实际应用不可能这样加密。
  7. out.writeInt(age);
  8. }
  9. //反序列化
  10. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  11. //in.defaultReadObject();// 从此流读取当前类的非静态和非瞬态字段。
  12. //如果不写,其他字段就不能被反序列化
  13. name = ((StringBuffer)in.readObject()).reverse().toString(); //解密
  14. age = in.readInt();
  15. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

详细的自定义序列化与反序列化可参见ObjectOutputStream 和ObjectInputStream 类的JDK文档。

Externalizable接口

Externalizable接口 与Serializable 接口类似,只是Externalizable接口需要强制自定义序列化。 
要序列化对象的代码:

  1. public class Teacher implements Externalizable{
  2. private String name;
  3. private Integer age;
  4. public Teacher(){
  5. System.out.println("无参构造");
  6. }
  7. public Teacher(String name,Integer age){
  8. System.out.println("有参构造");
  9. this.name = name;
  10. this.age = age;
  11. }
  12. //setter、getter方法省略
  13. @Override
  14. public void writeExternal(ObjectOutput out) throws IOException {
  15. out.writeObject(new StringBuffer(name).reverse()); //将name简单加密
  16. //out.writeInt(age); //注掉这句后,age属性将不能被序化
  17. }
  18. @Override
  19. public void readExternal(ObjectInput in) throws IOException,
  20. ClassNotFoundException {
  21. name = ((StringBuffer) in.readObject()).reverse().toString();
  22. //age = in.readInt();
  23. }
  24. @Override
  25. public String toString() {
  26. return "[" + name + ", " + age+ "]";
  27. }
  28. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

主函数代码改为:

  1. public class MySerilizable {
  2. public static void main(String[] args) throws Exception {
  3. File file = new File("person.txt");
  4. //序列化持久化对象
  5. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
  6. Teacher person = new Teacher("Peter", 27);
  7. out.writeObject(person);
  8. out.close();
  9. //反序列化,并得到对象
  10. ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
  11. Object newPerson = in.readObject(); // 没有强制转换到Person类型
  12. in.close();
  13. System.out.println(newPerson);
  14. }
  15. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

打印结果:

  1. 有参构造
  2. 无参构造 //与Serializable 不同的是,还调用了无参构造
  3. [Peter, null] //age未被序列化,所以未取到值
  • 1
  • 2
  • 3

八、单例模式的序列化

当我们使用Singleton模式时,应该是期望某个类的实例应该是唯一的,但如果该类是可序列化的,那么情况可能略有不同。此时对第2节使用的Person类进行修改,使其实现Singleton模式,如下所示:

  1. public class Person implements Serializable {
  2. private static class InstanceHolder {
  3. private static final Person instatnce = new Person("John", 31, "男");
  4. }
  5. public static Person getInstance() {
  6. return InstanceHolder.instatnce;
  7. }
  8. private String name = null;
  9. private Integer age = null;
  10. private Gender gender = null;
  11. private Person() {
  12. System.out.println("无参构造");
  13. }
  14. private Person(String name, Integer age, String gender) {
  15. System.out.println("有参构造");
  16. this.name = name;
  17. this.age = age;
  18. this.gender = gender;
  19. }
  20. ...
  21. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

同时要修改MySerilizable 应用,使得能够保存/获取上述单例对象,并进行对象相等性比较,如下代码所示:

  1. public class MySerilizable {
  2. public static void main(String[] args) throws Exception {
  3. File file = new File("person.txt");
  4. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
  5. out.writeObject(Person.getInstance()); // 保存单例对象
  6. out.close();
  7. ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
  8. Object newPerson = in.readObject();
  9. in.close();
  10. System.out.println(newPerson);
  11. System.out.println(Person.getInstance() == newPerson); // 将获取的对象与Person类中的单例对象进行相等性比较
  12. }
  13. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

打印结果:

  1. 有参构造
  2. [John, 31, 男]
  3. true //说明是同一个对象
  • 1
  • 2
  • 3

九、序列化对象注意事项

  1. 对象的类名、属性都会被序列化;而方法、static属性(静态属性)、transient属性(即瞬态属性)都不会被序列化(这也就是第4条注意事项的原因)
  2. 虽然加static也能让某个属性不被序列化,但static不是这么用的
  3. 要序列化的对象的引用属性也必须是可序列化的,否则该对象不可序列化,除非以transient关键字修饰该属性使其不用序列化。
  4. 反序列化地象时必须有序列化对象生成的class文件(很多没有被序列化的数据需要从class文件获取)
  5. 当通过文件、网络来读取序列化后的对象时,必须按实际的写入顺序读取。

Java基础--对象的序列化的更多相关文章

  1. Java实现对象的序列化

    什么是对象的序列化? 序列化:把对象转化成字节序列的过程就是对象的序列化:反序列化:把字节序列转化成对象的过程就是对象的反序列化.单看概念比较抽象,但是看代码就会明白. 对象序列化的用途 1.Java ...

  2. 《java基础——对象的拷贝》

    java基础--对象的拷贝 一.浅拷贝: 规则: 1. 浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对象的值也会发生变化. 2. 浅拷贝相当于两个对象共用一套实例. 格式: 类名 对象 ...

  3. Java基础--对象的克隆

    文章转载自https://www.cnblogs.com/Qian123/p/5710533.html 阅读目录 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 假如说你想复制一 ...

  4. Java基础知识:序列化和反序列化

    一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存 ...

  5. java中对象的序列化和反序列化

    [对象的序列化和反序列化 ] 1.定义:序列化--将对象写到一个输出流中.反序列化则是从一个输入流中读取一个对象.类中的成员必须是可序列化的,而且要实现Serializable接口,这样的类的对象才能 ...

  6. Java:对象的序列化

    一.对象序列化机制 序列化机制允许将实现序列化的Java对象转换为字节序列,这些字节序列可以被保存在磁盘上或通过网络传输,以备以后重新恢复原来的对象: 序列化机制使得对象可以脱离程序的运行而独立存在: ...

  7. 《Java基础知识》序列化与反序列化详解

    序列化的作用:为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制. 序列化应用场景: 1. 分布式传递对象. 2. 网络传递对象. 3. tomcat关闭以后会把session对象序列 ...

  8. java基础-对象的初始化

    一 前言 本节内容将会提到方法重载,对象的初始化,对象的构造器,和this关键字的使用,以及会简要的概括一下java中对象回收机制.觉得文章不错的读者可以关注一下作者的博客和公众号(同博客名称) 二 ...

  9. Java基础/利用fastjson序列化对象为JSON

    利用fastjson序列化对象为JSON 参考博客:http://blog.csdn.net/zeuskingzb/article/details/17468079 Step1:定义实体类 //用户类 ...

随机推荐

  1. Adjoint of SE(3)

    以前看的书都提到 SE(3) 和 se(3) 的 Adjoint,但是并没有讲这个东西是干什么用的,只是给了一堆性质.这东西来自群论. 参考 Lie Groups for 2D and 3D Tran ...

  2. java 两个list 交集 并集 差集 去重复并集

    前提需要明白List是引用类型,引用类型采用引用传递. 我们经常会遇到一些需求求集合的交集.差集.并集.例如下面两个集合: List<String> list1 = new ArrayLi ...

  3. Django开发笔记三

    Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.基于类的方式重写登录:views.py: from ...

  4. Reverse Words in a String I & Reverse Words in a String II

    Reverse Words in a String I Given an input string, reverse the string word by word. For example,Give ...

  5. 所有Windows7下游戏的全屏问题

    Win键+R键,打开运行窗口,输入regedit 回车,这样就打开了注册表编辑器,然后,定位到以下位置:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\ ...

  6. WebSphere的jython编码的一个坑

    was5.1版本,用"name=" in line这类判断字符串包含的方式时,系统会提示报错 TypeError: string member test needs char le ...

  7. 『转载』hadoop 1.X到2.X的变化

    表1新旧hadoop脚本/变量/位置变化表 改变项 原框架中 新框架中(Yarn) 备注 配置文件位置 ${hadoop_home_dir}/conf ${hadoop_home_dir}/etc/h ...

  8. PHP框架CodeIgniter--URL去除index.php

    今天学习CodeIgniter简称CI的第一天,记录下学习心得. CI中国https://codeigniter.org.cn/user_guide/general/urls.html?highlig ...

  9. linux下混杂模式

    混杂模式介绍: 混杂模式就是接收所有经过网卡的数据包,包括不是发给本机的包,默认情况下网卡只把发给本机的包(包括广播包)传递给上层程序,其它的包一律丢弃:简单的讲,混杂模式就是指网卡能接受所有通过它的 ...

  10. centos7 Firewalld操作集合

    =============================================== 2019/4/15_第1次修改                       ccb_warlock == ...