1.什么是序列化?
把Java对象转换为字节序列的过程称为对象的序列化,把字节序列恢复为Java对象的过程称为对象的反序列化。
对象的序列化主要有如下2种用途:
- 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中
- 在网络上传送对象的字节序列
2.序列化的实现方式
- 类继承Serializable接口,可使用writeObject方法和readObject方法控制类序列化的过程。 默认情况下只会初始化化非transient得实例变量。 一般使用writeObject方法和readObject方法来优化序列化的过程或者对敏感数据进行特殊的处理。
package com.wilian.serialize; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Date; import java.util.List; /** * * @author wilian * */ //通过实现Serializable接口实现序列化 public class Comsumer implements Serializable { private static final long serialVersionUID = -6701934960639960628L; public static int MAX_BILL =2000; private String name; private Date birthday; private transient String password; private List<Order> orders; static{ //反序列化不会调用静态初始化块 System.out.println("静态初始化块"); } public Comsumer() { //反序列化不会构造方法 System.out.println("正在创建一个Comsumer"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public List<Order> getOrders() { return orders; } public void setOrders(List<Order> orders) { this.orders = orders; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private void writeObject(ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); out.writeObject(this.password); } private void readObject(ObjectInputStream in)throws IOException, ClassNotFoundException{ in.defaultReadObject(); this.password=(String)in.readObject(); } }
package com.wilian.serialize; import java.io.Serializable; //通过实现Serializable接口实现序列化 public class Order implements Serializable{ private static final long serialVersionUID = -4383674802849314614L; private String orderNo; private int money; public String getOrderNo() { return orderNo; } public void setOrderNo(String orderNo) { this.orderNo = orderNo; } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } }
package com.wilian.serialize; 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.util.ArrayList; import java.util.Date; import java.util.List; public class SerializedTest { public static void main(String[] args) { ObjectOutputStream oos =null; ObjectInputStream ois =null; try { FileOutputStream fos = new FileOutputStream( new File("D://cumsumer.dat")); oos = new ObjectOutputStream(fos); Comsumer comsumer= new Comsumer(); comsumer.setBirthday(new Date()); comsumer.setName("wilian"); comsumer.setPassword("12345678"); List<Order> orders=new ArrayList<Order>(); Order order1 = new Order(); order1.setMoney(15); order1.setOrderNo("001"); orders.add(order1); Order order2 = new Order(); order2.setMoney(19); order2.setOrderNo("002"); orders.add(order2); comsumer.setOrders(orders); oos.writeObject(comsumer); FileInputStream fis = new FileInputStream( new File("D://cumsumer.dat")); ois=new ObjectInputStream(fis); Comsumer c =(Comsumer) ois.readObject(); //验证两个对象是否相等 System.out.println(comsumer==c); System.out.println(comsumer.equals(c)); // System.out.println(c.getName()); System.out.println(c.getBirthday()); System.out.println(c.getPassword()); System.out.println(c.getOrders().size()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); }finally{ if(oos!=null) try { oos.close(); } catch (IOException e) { e.printStackTrace(); } if(ois!=null) try { ois.close(); } catch (IOException e) { e.printStackTrace(); } } } }
- 实现Externalizable接口;Externalizable接口继承自Serializable接口,可以完全控制类的序列化行为。与Serializable另外个不同之处:一个类如果实现了Externalizable接口,那么它必须具有public类型的不带参数的构造方法,否则这个类无法反序列化。
package com.wilian.serialize; import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.util.Date; public class Dog implements Externalizable { protected String name; protected int weight; protected Date birthday; public Dog(String name, int weight, Date birthday) { this.name = name; this.weight = weight; this.birthday = birthday; } //要提供public无参构造方法否则会抛出如下异常 //java.io.InvalidClassException: com.wilian.serialize.Dog; no valid constructor public Dog(){}; @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeInt(weight); out.writeObject(birthday); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name=(String)in.readObject(); weight=in.readInt(); birthday=(Date)in.readObject(); } public static void main(String[] args) { try { FileOutputStream fos = new FileOutputStream( new File("D://dog.dat")); ObjectOutputStream oos = new ObjectOutputStream(fos); Dog dog=new Dog("Wangcai",25,new Date()); oos.writeObject(dog); oos.close(); FileInputStream fis = new FileInputStream( new File("D://dog.dat")); ObjectInputStream ois = new ObjectInputStream(fis); Dog dog1 =(Dog) ois.readObject(); ois.close(); System.out.println(dog1.name); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
3.序列化中readResolve()方法的应用
由上面的例子可以看出序列化出来的对象与序列化之前的对象非同一个对象,如果在有些单例的场景这样就违反了JVM中只有一个实例的约定。如果一个类提供了readResolve方法,那么在执行反序列化操作时,先按照默认方式或者用户自定义的方式进行反序列化,最后再调用readResolve方法,该方法返回的对象为反序列化的最终结果。
package com.wilian.serialize; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; import java.io.Serializable; public class SystemConfig implements Serializable { /** * */ private static final long serialVersionUID = 4026591699359366802L; private static final SystemConfig instance =new SystemConfig(); private String ip; private String host; private int port; private SystemConfig(){ this.ip="127.0.0.1"; this.host="localhost"; this.port=8080; } public static SystemConfig getInstance(){ return instance; } public String getIp() { return ip; } public String getHost() { return host; } public int getPort() { return port; } /** * 返回值必须是Object,否则函数不生效 * 方法权限可以是private\默认\protected级别 * @return Object * @throws ObjectStreamException */ private Object readResolve() throws ObjectStreamException{ return instance; } public static void main(String[] args) { try { SystemConfig config=SystemConfig.getInstance(); ByteArrayOutputStream buf = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(buf); oos.writeObject(config); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray())); SystemConfig config1 = (SystemConfig)ois.readObject(); System.out.println(config1==config); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
4.serialVersion序列化版本的作用
serialVersionUID有两种用途:
- 希望不同版本对序列化兼容,因此需要确保类的不同版本具有相同的seriaVersionUID;
- 不希望不同版本对序列化兼容,因此需要确保类的不同版本具有不同的seriaVersionUID;
当一个类的不同版本的seriaVersionUID相同,仍然有可能出现序列化不兼容的情况。
相关推荐
Java序列化是Java平台中的一种持久化机制,它允许对象的状态被转换成字节流,以便存储、网络传输或在不同时间点恢复。这个过程被称为序列化,而反向操作称为反序列化。序列化在许多场景下都非常有用,比如在分布式...
java 序列化和反序列化的方法 Java 序列化和反序列化是 Java 语言中的一种机制,用于将对象转换为字节流,以便在网络上传输或存储。序列化是将对象转换为字节流的过程,而反序列化是将字节流转换回对象的过程。 在...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化的概念 序列化是指将程序中的对象转换为一系列字节流的过程,主要用于保存对象的状态或在网络之间传输对象。序列化的主要目的是为了能够持久化...
【Protocol Buffer序列化对比Java序列化】 Protocol Buffer(简称PB)是Google开发的一种高效的数据序列化协议,而Java序列化是Java平台内置的一种序列化机制。两者的主要目标都是将对象转化为字节数组,便于在网络...
Java序列化是Java平台提供的一种持久化机制,它允许我们将一个Java对象转换为字节流,以便存储到磁盘上,或者通过网络进行传输。这使得我们可以保存和恢复对象的状态。实现序列化的类需要实现`Serializable`接口,...
Java序列化是Java平台中的一种核心机制,它允许对象的状态被转换成字节流,以便存储到磁盘、数据库,或者在网络中进行传输。这对于实现持久化、远程方法调用(RMI)以及Enterprise JavaBeans(EJB)等高级功能至关...
### Java序列化(Serializable)的作用与反序列化详解 #### 一、序列化是什么? 序列化是指将程序中的对象转换为字节流的过程,从而方便存储或传输这些对象。通常,序列化用于将对象的状态(即其实例变量的值,而非...
Java序列化是Java平台中的一种标准机制,它允许将对象的状态转换为字节流,以便存储、传输或恢复。在Java中,一个类如果要实现序列化,需要实现`Serializable`接口,这是一个标记接口,不包含任何方法。下面我们将...
Java序列化是Java平台中的一项重要技术,它允许对象的状态被转换为字节流,以便存储或通过网络进行传输。这种技术在分布式系统、持久化存储以及数据交换等场景中非常常见。本资源包含了三个流行的Java序列化框架:...
Java序列化是Java平台提供的一种将对象转换为字节流,以便存储、在网络上传输或者在后续时间重新创建相同对象的机制。这是Java编程中一个非常重要的概念,尤其是在分布式环境和持久化存储中。让我们深入探讨一下Java...
### Java序列化原理与算法详解 #### 序言 在现代软件开发中,尤其是在网络通信和数据持久化领域,对象的序列化与反序列化扮演着至关重要的角色。Java作为一种广泛应用的编程语言,提供了强大的内置支持来实现序列化...
Java序列化面试题(10题) 在 Java 中,序列化是一种用于处理对象流的机制,它可以将对象的内容进行流化,使其可以被读写和传输。下面是 10 个与 Java 序列化相关的面试题目: 1. 什么是 Java 序列化,如何实现 ...
Java序列化是Java平台中的一种标准机制,允许对象的状态被保存到磁盘或者在网络中进行传输,以便在后续的时间或地点恢复这些对象。这个过程包括两个主要操作:序列化(将对象转换为字节流)和反序列化(将字节流恢复...
Java序列化是Java平台提供的一种持久化对象的机制,它允许我们将对象的状态转换为字节流,以便存储或在网络上传输。在这个特定的场景中,我们关注的是如何使用Java序列化来多次追加对象到一个TXT文件,而不是覆盖...
### Java序列化与反序列化详解 #### 一、Java序列化概述 Java序列化(Serialization)是一项重要的功能,它可以将对象的状态转化为一系列字节,从而实现对象的持久化存储或在网络上传输。序列化机制使得Java对象...
### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的...以上内容涵盖了Java序列化标准的关键知识点,深入了解这些概念有助于更好地理解和应用Java序列化技术。
Java序列化漏洞是一种常见的安全问题,它出现在Java应用程序中,当对象被转化为字节流以便在网络间或存储中传输时。这种序列化过程如果处理不当,可能会导致远程代码执行(RCE)、信息泄露或者权限提升等严重后果。...
android(包括java)序列化一个对象传给php去做处理,或是接到php的序列化的对象在java中做处理的工具jar包以及使用方法. 使用方法: byte[] b = null; b = PHPSerializer.serialize(一个对象);//将一个对象序列化后返回...
Java序列化是将Java对象转换为字节流的过程,以便可以在网络上传输或存储在磁盘上。这使得数据能够跨不同的系统平台进行传输和持久化。Protocol Buffers(protobuf)是Google推出的一种高效、跨平台的数据序列化协议...