本文共 7327 字,大约阅读时间需要 24 分钟。
目录
序列化:即提取数据对象并将其转换为字节流(二进制格式)的过程,因此它可以通过网络传输或保存在数据库、以及本地文件中,后续可以再反序列化为对象。
实现 Serializable 接口
1、使用默认的序列化机制,即实现 Serializable 接口即可,不需要实现任何方法。
2、Serializable 接口没有任何方法,只是一个标记而已,告诉Java虚拟机该类可以被序列化了。利用 ObjectOutputStream 的writeObject(object) 方法进行序列化,用 ObjectInputStream 的 readObject() 方法进行反序列化。
3、该方式下序列化机制会自动保存该对象的成员变量,static 成员变量和 transient 关键字修饰的成员变量不会被序列化保存
准备 User 实体类如下:
import java.io.Serializable;import java.util.Date;/** * Created by Administrator on 2018/7/31 0031. * 用户类----实现 Serializable 接口 */public class User implements Serializable { private static final long serialVersionUID = 1749243243491717954L;//具体数值自己定义 private Integer id; private String name; private Date birthday; private static String address = "China";//默认情况下,静态属性不会被序列化 public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public static String getAddress() { return address; } public static void setAddress(String address) { User.address = address; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", birthday=" + birthday + '}'; }}
序列化如下:
import java.io.*;import java.util.Date;/** * Created by Administrator on 2018/7/25 0025. */public class Test { public static void main(String[] args) { User user = new User(); user.setId(9527); user.setName("华安"); user.setBirthday(new Date()); User.setAddress("USA"); String path = "D:/abc.txt";//序列化保存在本地的位置 new Test().serialize(user, path); } /** * 将对象序列化到指定文件 * * @param user * @param path */ public void serialize(User user, String path) { try { FileOutputStream fileOutputStream = new FileOutputStream(new File(path)); ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); objectOutputStream.writeObject(user); objectOutputStream.flush(); objectOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }}
代码运行后,就会在 D:/abc.txt 文件中保存好序列化后的数据。
反序列化:
import java.io.*;/** * Created by Administrator on 2018/7/25 0025. */public class Test { public static void main(String[] args) { String path = "D:/abc.txt";//序列化保存在本地的位置 new Test().deserialize(path); } /** * 从文件反序列化 * * @param path */ public void deserialize(String path) { try { FileInputStream fileInputStream = new FileInputStream(new File(path)); ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); Object user = objectInputStream.readObject(); objectInputStream.close(); System.out.println("反序列化结果 user :" + user); System.out.println("反序列化结果 User.getAddress():" + User.getAddress()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }}
控制台输出如下:
反序列化结果 user :User{id=9527, name='华安', birthday=Wed Jul 10 14:46:09 CST 2019}
反序列化结果 User.getAddress():China
serialVersionUID 版本号
1、序列化后,如上 User 所示,其中通常都会一行代码:private static final long serialVersionUID = 1749243243491717954L;
2、假设类 A 实现 Serializable 接口,当使用序列化将对象传输到了其它地方,此时因为一些原因修改了类 A(比如添加属性、删除属性、修改属性等),那么之前序列化后的数据能否再反序列化为对象呢?
1)如果类中自定义了 serialVersionUID 属性,且值未发生变化,则可以正确反序列化回来。
2)如果类中没有自定义 serialVersionUID 属性,则此时无法反序列化为对象,并报错如下:
java.io.InvalidClassException: wmx.com.springboothello.test.User; local class incompatible: stream classdesc serialVersionUID = -4467989014877592694, local class serialVersionUID = -7572413328418759383
3、假设类 B 实现 Serializable 接口,类中没有自定义 serialVersionUID 属性,则序列化时会根据算法得到一个默认值,之后只要类 B 没有做修改,则这个默认的 serialVersionUID 值会一直不变,反序列化也就不会有问题。如果之后类 B 发生了变化,则此时它的 serialVersionUID 也会发生变化,旧的 serialVersionUID 值反序列化时就会因为值不匹配新值而发生如上错误。
4、同理假如类 C 实现 Serializable 接口,类中自定义了 serialVersionUID 属性值,后面如果修改了类 C ,但只要 serialVersionUID 属性值不变,则之前序列化的内容仍然可以正常反序列化。如果此时不想再让以前序列化的内容能反序列化成功,则只需要手动修改 serialVersionUID 属性值即可。
5、serialVersionUID 属性值可以自己随意指定,但是名称必须写死,如果写成 suid、seriaUID等等都是无效的。
IDEA 快捷键生成 serialVersionUID
1、打开 IDEA setting 窗口后直接搜索 "serialVersionUID",然后将 serializable class without ‘serialVersionUID’ 勾选上
2、需要生成 serialVersionUID 的类先实现 Serializable 接口
3、最后鼠标点击需要生成的类名,按下快捷键 alt+entry,即可选择进行生成。
序列化方式克隆对象
1、对于 Java Bean(POJO对象)可以使用 Spring BeanUtils、、 等库,
但是它们用的是反射机制,所以只对 Java bean 有效,而且 POJO 对象还必须提供 getter、setter 方法,而对 Map、List、Set 等数据结构无法复制。
2、所以对于项目中经常遇到的 Map、List、Set 等等数据结构,使用序列化的方式可以对其进行克隆。
import org.junit.Test;import java.io.*;import java.util.*;/** * Java 对象深度克隆 * * @author wangMaoXiong * @version 1.0 * @date 2020/7/31 16:39 */public class DeepCopyTest { /** * Map 对象深度复制 * * @param src 被克隆的对象,如:Map、Map 等等 * @param * @param :支持任意类型,如果是 java Bean,则必须实现 {@link Serializable} 接口实现序列化,否则报错 * @return * @throws IOException * @throws ClassNotFoundException */ public static Map deepCopy(Map src) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); Map dest = (Map ) in.readObject(); return dest; } /** * List 对象深度复制 * * @param src :被克隆的对象,如:List 、List
对象克隆在线测试源码:
转载地址:https://wangmaoxiong.blog.csdn.net/article/details/81295418 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!