Java - 【序列化】序列化与克隆

    科技2026-02-08  2

    序列化与克隆

    → 推荐:《刀剑神域-序列之争》

    序列化 序列化只保存类的属性信息 反序列化serialversionUID 作用IDEA配置警告 序列化中常见的两类异常 java.io.NotSerializableExceptionjava.io.InvalidClassException 克隆 浅克隆深克隆(序列化)序列化相关类的继承关系

    一:序列化

    /** * 序列化指定Person对象 * 序列化只会保存原有类的属性; * * @param p 待序列化对象 * @throws IOException */ public static void serializePerson(Person p) throws IOException { // 创建文件夹和文件 String personFileDirPath = System.getProperty("user.dir")+"\\person"; File seriableFileDir = new File(personFileDirPath); if(!seriableFileDir.exists()){ seriableFileDir.mkdir(); } String personFilePath = System.getProperty("user.dir")+"\\person\\p1.person"; File seriableFile = new File(personFilePath); if(!seriableFile.exists()){ seriableFile.createNewFile(); } if(p!=null){ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(personFilePath)); oos.writeObject(p); } }

    二:反序列化

    /** * 根据文件反序列化指定对象 * 序列化只会保存原有类的属性; * 反序列化时,只需要获得被序列化类的serialVersionUID+待获取属性+类名 * 类名打开序列化文件第二行开头可以发现 * * @param filePath 序列化对象文件 * @return 反序列化后的对象 */ public static Person deSerializePerson(String filePath) throws IOException, ClassNotFoundException { if(filePath!=null||!filePath.trim().equals("")) { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath)); return (Person) ois.readObject(); } return null; }

    三:serialVersionUID

    作用

    用于标记可序列化对象 (private static final long),对指定文件进行反序列化时需要验证源与目标具有相同的UID

    java.io.InvalidClassException: xyz.xx.Person; local class incompatible: stream classdesc serialVersionUID = 3437483674491733544, local class serialVersionUID = 2215763102943453354 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1939) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1805) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2096) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422) at xyz.xx.Test.deSerializePerson(Test.java:60) at xyz.xx.Test.main(Test.java:18)

    如果UID没有显示指明,类会自动根据当前类的信息摘要出一个serialVersionUID,当类的内容发生改变时,该默认生成的UID会发生很大的变化;

    IDEA配置警告(未显式定义serialVersionUID时给与警告)

    四:序列化中常见的两类异常

    java.io.NotSerializableException

    被序列化的类没有实现Serializable接口

    java.io.InvalidClassException

    反序列化对象UID与本地类UID不匹配

    五:克隆

    实现Clonable接口

    java.lang.CloneNotSupportedException

    重写Object类中的clone方法

    @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }

    六:浅克隆与深克隆测试

    Person.java

    package xyz.xx; import java.io.Serializable; public class Person implements Serializable { private static final long serialVersionUID = 3437483674491733544L; private String name; private int age; private boolean gender; public Person(){} public Person(String name, int age, boolean gender) { this.name = name; this.age = age; this.gender = gender; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public boolean isGender() { return gender; } public void setGender(boolean gender) { this.gender = gender; } }

    Student.java

    package xyz.xx; import java.io.Serializable; public class Student extends Person implements Serializable { private static final long serialVersionUID = -7461432514299767086L; private int score; public Student(){} public Student(String name, int age, boolean gender) { super(name, age, gender); } public int getScore() { return score; } public void setScore(int score) { this.score = score; } @Override public String toString() { return super.getName()+"-"+super.getAge()+"-"+(super.isGender()?"男":"女")+":"+score; } }

    Teacher.java

    内部使用序列化实现deepClone()

    package xyz.xx; import java.io.*; public class Teacher extends Person implements Cloneable, Serializable { private static final long serialVersionUID = -1883148076584384389L; private Student student; public Teacher(){} public Teacher(String name, int age, boolean gender, Student student) { super(name, age, gender); this.student = student; } public Student getStudent() { return student; } public void setStudentScore(int score) { this.student.setScore(score); } public Teacher deepClone() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (Teacher)ois.readObject(); } @Override public String toString() { return super.getName()+"-"+super.getAge()+"-"+(super.isGender()?"男":"女")+":"+student; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }

    Test.java

    package xyz.xx; /** * 下方两次获取逻辑不同,注意 * * false * true * 学生A-18-女:99 * 学生A-18-女:99 * false * false * 学生A-18-女:199 * 学生A-18-女:99 */ public class Test { public static void main(String[] args) { Student s1 = new Student("学生A",18,false); Teacher t1 = new Teacher("教师A",37,false,s1); try { Teacher t2 = (Teacher)t1.clone(); System.out.println(t1==t2); // true System.out.println(t1.getStudent()==t2.getStudent()); t1.setStudentScore(99); // 修改t1影响t1和t2 System.out.println(t1.getStudent()); System.out.println(t2.getStudent()); Teacher t3 = t1.deepClone(); System.out.println(t1==t3); // false System.out.println(t1.getStudent()==t3.getStudent()); t1.setStudentScore(199); // 修改t1只影响t1 System.out.println(t1.getStudent()); System.out.println(t3.getStudent()); } catch (Exception e) { e.printStackTrace(); } } }

    七:序列化相关类的继承关系

    Processed: 0.018, SQL: 9