JAVA序列化

本文深入探讨了Java串行化技术的概念、特点及其在序列化实现中的应用,包括如何利用串行化机制将对象状态持久化到数据库、文件系统或网络传输中,以及在不同场景下的具体操作步骤。

欢迎大家访问我的新网站我的新网站

1.串行化的概念

Java串行化技术可以使你将一个对象的状态写入到Byte流里,并且可以从其他地方把Byte流里的数据读出来,
重新构造一个相同的对象。这种机制允许你将对象通过网络进行传播,并可以随时把对象持久化到数据库、文件系统里。Java的串行化机制是RMI、EJB等技术的技术基础。用途:利用对用的串行化实现保存应用程序的当前状态,下次在启动的时候就自动地-恢复到上次执行的状态。

序列化就是一种用来处理对象流的机制。所谓对象流也就是将对象的内容进行流花。可以对流化后的对象进行读写操作,也可以将流化后的对象传输与网络之间。序列化是为了解决在对对象进行读写操作时所引发的问题。

序列化的实现:将需要序列化的类实现Serializable接口,然后使用一个输出流(如:FileOutputSteam)来构造一个ObjectOutputStream(对象流)对象。接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数obj对象写出(即保存其状态),要恢复的话则使用输入流。

2.串行化的特点

  1. 如果某个类能够被串行化,其子类也可以被串行化。如果该类有父类,则分为2种情况来考虑。如果该父类已经实现了可串行化接口,则父类的相应字段及属性的处理和该类相同;如果该类的父类没有实现可串行化接口,则该类的父类所有的字段属性将不会串行化。
  2. 声明为static和transient类型的成员数据不能被串行化。因为static代表类的状态,transient代表对象的临时数据。
  3. 相关的接口和类:在java.io包中提供的设计对象的串行化的雷雨接口有ObjectOutput接口,ObjectOutputStream类,ObjectInput接口,ObjectInputStream类。
  4. ObjectOutput接口:集成DataOutput接口,并且支持对对象的串行化,其内的writeObject()方法实现存储一个对象。ObjectInput接口:继承DateInput接口并且支持对象的串行化,其内的readObject()方法实现读取一个对象。
  5. ObjectOutputStream类:继承OutputStream类并且实现ObjectOutput接口。利用该类来实现将对象存储(调用ObjectOutput接口中的writeObject()方法)。ObjectInputStream类:继承InputStream类并且实现了ObjectInput接口,利用该类来实现读取一个对象(嗲用ObjectInput接口中的readObject()方法)。

对于父类的处理,如果父类没有实现串行化接口,则必须有默认的构造函数,否则编译的时候就会报错。在反串行化的时候,默认构造函数会被调用。但是若把父类标记为可串行化,则在反串行化的时候,其默认的构造函数不会被调用,这是因为Java对传闲话的对象进行反串行化的时候,直接从流利获取其对象数据生成一个对象实例,而不是通过其构造函数来完成。

以下是一个Java串行化的例子

import java.io.*;
public class Cat implements Serializable {
        private String name;
        public Cat () {
                this.name = "new cat";
        }
        public String getName() {
                return this.name;
        }
        public void setName(String name) {
                this.name = name;
        }
        public static void main(String[] args) {         
                Cat cat = new Cat();
                try {
                        FileOutputStream fos = new FileOutputStream("catDemo.out");
                        ObjectOutputStream oos = new ObjectOutputStream(fos);
                        System.out.println(" 1> " + cat.getName());
                        cat.setName("My Cat");                       
                        oos.writeObject(cat);
                        oos.close();                       
                } catch (Exception ex) {  ex.printStackTrace();   }
                try {
                        FileInputStream fis = new FileInputStream("catDemo.out");
                        ObjectInputStream ois = new ObjectInputStream(fis);
                        cat = (Cat) ois.readObject();
                        System.out.println(" 2> " + cat.getName());
                        ois.close();
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
        }
}//writeObject和readObject本身就是线程安全的,传输过程中是不允许被并发访问的。所以对象能一个一个接连不断的传过来


### 序列化的含义 序列化指将堆内存中的 Java 对象数据,通过某种方式存储到磁盘文件中,或者传递给其他网络节点(网络传输),即将对象转化为二进制,用于保存或网络传输。反序列化则是从 IO 流中恢复对象[^1][^4]。 ### 序列化的意义 序列化机制允许将实现序列化Java 对象转换为字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在[^1]。 ### 序列化的使用场景 所有可在网络上传输的对象都必须是可序列化的,比如 RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的 Java 对象都必须是可序列化的。通常建议程序创建的每个 JavaBean 类都实现 Serializable 接口[^1]。 ### 序列化实现的方式 #### Serializable 接口 - **普通序列化**:实现 Serializable 接口后,可使用 ObjectOutputStream 将对象写入流,使用 ObjectInputStream 从流中读取对象。 ```java import java.io.*; class Person implements Serializable { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } } public class SerializationExample { public static void main(String[] args) { Person person = new Person("John", 30); try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) { oos.writeObject(person); } catch (IOException e) { e.printStackTrace(); } try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) { Person deserializedPerson = (Person) ois.readObject(); System.out.println(deserializedPerson.name + " " + deserializedPerson.age); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } } ``` - **成员是引用的序列化**:若类的成员是引用类型,该引用类型也必须是可序列化的,否则当前类无法实现序列化。 - **同一对象序列化多次的机制**:Java 序列化算法会保证同一对象多次序列化时,不会重复序列化对象的内容,而是只记录对象的引用。 - **Java 序列化算法潜在的问题**:例如序列化版本号不匹配、性能问题等。 - **可选的自定义序列化**:可通过实现 `writeObject` 和 `readObject` 方法来自定义序列化和反序列化过程。 #### Externalizable 接口 Externalizable 接口强制自定义序列化,需要实现 `writeExternal` 和 `readExternal` 方法。 ```java import java.io.*; class Employee implements Externalizable { String name; int id; public Employee() {} public Employee(String name, int id) { this.name = name; this.id = id; } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(name); out.writeInt(id); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { name = (String) in.readObject(); id = in.readInt(); } } ``` ### 序列化版本号 serialVersionUID serialVersionUID 用于确保序列化和反序列化时类的版本一致性。若没有显式定义 serialVersionUID,Java 会根据类的结构自动生成一个。当类的结构发生变化时,可能会导致 serialVersionUID 改变,从而在反序列化时抛出 `InvalidClassException`。建议显式定义 serialVersionUID。 ```java import java.io.Serializable; class MyClass implements Serializable { private static final long serialVersionUID = 1L; // 类的成员和方法 } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值