직렬화를 소개하기 전에 먼저 다음 개념을 알아야 합니다.
비지속성: JVM(Java Virtual Machine)에 존재하는 객체의 경우 내부 상태는 JVM이 실행될 때 메모리에서만 유지될 수 있습니다. 작동을 멈추면 내부 상태가 사라지므로 비지속적입니다.
지속성: 개체를 영구적으로 저장하려는 경우(예: 지속성) 일반적인 접근 방식은 개체를 파일 또는 데이터베이스.
직렬화해야 합니다. 직렬화를 통해 활성 JVM에서 객체를 쉽게 직렬화할 수 있습니다. 객체는 저장을 위해 바이트 배열(스트림)로 변환됩니다.
class Person implements Serializable { private String name; private int age; public Person(String name ,int age){ this.name = name; this.age =age; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString() { return "name is " + name + " , age is " + age; } }public class Test { private final static String TEMPFILE = "E:" + File.separator + "test.txt"; public static void main(String[] args) { Person person = new Person("test",100); write(person); // 关键 -> 序列化之后重新对对象进行赋值 person = new Person("hello",999); read(person); // 输出结果: // name is test , age is 100,序列化成功 // 反序列化成功,name is test , age is 100 } // 通过 ObjectOutputStream 进行对象的序列化操作 private static void write(Person person) { try { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(TEMPFILE)); oos.writeObject(person); oos.close(); System.out.println(person+",序列化成功"); } catch (Exception e) { e.printStackTrace(); } } // 通过 ObjectInputStream 进行对象的反序列化操作 private static void read(Person person) { try { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(TEMPFILE)); person = (Person) ois.readObject(); ois.close(); System.out.println("反序列化成功.,"+person); } catch (Exception e) { e.printStackTrace(); } } }출력 결과를 관찰합니다. 객체가 직렬화된 후 값을 다시 할당했는데 역직렬화 결과는 여전히 객체 이전의 값과 동일합니다. 일관성이 있다는 것은 객체가 영구적으로 저장되고 지속성이 달성된다는 것을 간접적으로 증명하는 것이기도 합니다.
직렬화 해제할 수 없음 ).
// 序列化过程、调用过程与上述例子一致,省略代码... // 这里只对内部类 Person 的 age 属性进行修改class Person implements Serializable { // 用 transient 修该变量 private transient int age; // 省略部分代码...} // 调用后的输出结果: // name is test , age is 100,序列化成功 // 反序列化成功.,name is test , age is 0출력을 관찰하여 직렬화 전 연령은 100이고 역직렬화를 통해 읽은 연령은 0임을 확인합니다. int 유형 매개변수의 초기값은 0입니다. 이는 매개변수가 직렬화되지 않았음을 의미합니다.
가 직렬화할 수 없다는 의미는 아닙니다 ).
// 序列化过程、调用过程与上述例子一致,省略代码... // 这里只对内部类 Person 的 name 属性进行修改class Person implements Serializable { // 用 static 修该变量 private static String name; // 省略部分代码...} // 输出结果: // name is test , age is 100,序列化成功//反序列化成功.,name is hello , age is 100출력 결과를 관찰해 보면 name의 값이 직렬화 전 테스트가 아닌 hello라는 것을 알 수 있었습니다. 앞과 뒤의 값이 다른 것은 연재되지 않았음을 나타냅니다. 그리고 static의 특성은 클래스와 관련이 있기 때문에 직렬화 작업 후에 변수를 다시 할당하여 그 값이 null이 아닌 hello가 되었습니다.
직렬화할 수 없습니다.
// 序列化过程、调用过程与上述例子一致,省略代码... // 这里只对内部类 Person 的 name 属性进行修改class Person implements Serializable { //新增成员变量 private Thread myThread = new Thread(); //省略部分代码...} // 输出结果(抛出异常): // Caused by: java.io.NotSerializableException: java.lang.Thread
// 序列化操作代码与上面一致... // 这里只对内部类 Person 的属性进行修改。class Person implements Serializable { private static String name; private transient int age; // 自定义序列化操作 private void writeObject(ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); out.writeObject(name); out.writeInt(age); } // 自定义反序列化操作 private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{ in.defaultReadObject(); name = (String) in.readObject(); age = in.readInt(); } // 省略部分代码...} // 输出结果: // name is test , age is 100,序列化成功 // 反序列化成功,name is test , age is 100
writeExternal 및 readExternal 메서드 구현을 강제합니다. 역직렬화 프로세스.
매개변수 없는 생성자 가 포함되어야 합니다.
// 序列化操作代码与上面一致,这里只对内部类 Person 的进行修改。 class Person implements Externalizable { private static String name; private transient int age; // 重点 ->必须有无参构造函数 public Person(){ } public Person(String name ,int age){ this.name = name; this.age =age; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString() { return "name is " + name + " , age is " + age; } // 实现接口的方法 @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeInt(age); } // 实现接口的方法 @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); age = in.readInt(); } } // 输出结果: // name is test , age is 100,序列化成功 // 反序列化成功,name is test , age is 100
메서드 가 수정되면 serialVersionUID **는 변경되지 않습니다**.
속성 이 수정되면 재생성된 serialVersionUID**가 변경됩니다**.
因此说明序列化是作用于对象属性上的。
下面通过实例来探究下 serialVersionUID 的具体作用:
首先我们对对象进行序列化操作(这里取消了反序列化的操作)
// 序列化操作代码与上面例子一致...// 这里取消了反序列化的操作public static void main(String[] args) { Person person = new Person("test",100); write(person); person = new Person("java", 200); //read(person);}
然后新增一个对象的属性,再进行反序列化操作
// 省略部分代码,与上面的代码一致...class Person implements Serializable { private String name; private age; //新增成员变量 private int phone; //省略部分代码... } }public static void main(String[] args) { Person person = new Person("test",100); //write(person); person = new Person("java", 200); read(person); }// 输出结果(抛出异常):// java.io.InvalidClassException: Person;
观察代码,在序列化对象并没有添加 serialVersionUID 的情况,在对象序列化之后如果改变了对象的属性,反序列化就会抛出异常。如果对象添加了 serialVersionUID 就不会出现这种情况,这里就不验证了。
以上就是13.Java 基础 - 序列化的内容,更多相关内容请关注PHP中文网(www.php.cn)!