Java--序列化

序列化

概述

Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据对象的类型对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。

反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化对象的数据对象的类型对象中存储的数据信息,都可以用来在内存中创建对象。看图理解序列化:

在这里插入图片描述

ObjectOutputStream

java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。

构造方法

  • public ObjectOutputStream(OutputStream out): 创建一个指定OutputStream的ObjectOutputStream。

构造举例,代码如下:

FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);

序列化操作

  1. 一个对象要想序列化,必须满足两个条件:
  • 该类必须实现java.io.Serializable 接口,Serializable 是一个标记接口,不实现此接口的类在序列化时会抛出NotSerializableException异常 。但是真正的序列化操作并不是通过它完成的。
    在这里插入图片描述
  • 该类的所有属性必须是可序列化的。如果有一个属性不需要可序列化的,则该属性必须注明是瞬态的,使用transient 关键字修饰,使用static关键字修饰的属性同样不可被序列化,因为序列化保存的是对象的状态而不是类的状态。
public class Employee implements Serializable {
    public String name;
    public String address;
    public transient int age; // transient瞬态修饰成员,不会被序列化
    public void addressCheck() {
      	System.out.println("Address  check : " + name + " -- " + address);
    }
}

2.写出对象方法

  • public final void writeObject (Object obj) : 将指定的对象写出。
public class SerializeDemo{
   	public static void main(String [] args)   {
    	Employee e = new Employee();
    	e.name = "zhangsan";
    	e.address = "beiqinglu";
    	e.age = 20; 
    	try {
      		// 创建序列化流对象
          ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.txt"));
        	// 写出对象
        	out.writeObject(e);
        	// 释放资源
        	out.close();
        	fileOut.close();
        	System.out.println("Serialized data is saved"); // 姓名,地址被序列化,年龄没有被序列化。
        } catch(IOException i)   {
            i.printStackTrace();
        }
   	}
}
输出结果:
Serialized data is saved

ObjectInputStream

ObjectInputStream反序列化流,将之前使用ObjectOutputStream序列化的原始数据恢复为对象。

构造方法

  • public ObjectInputStream(InputStream in): 创建一个指定InputStream的ObjectInputStream。
反序列化操作1

如果能找到一个对象的class文件,我们可以进行反序列化操作,调用ObjectInputStream读取对象的方法:

  • public final Object readObject () : 读取一个对象。
public class DeserializeDemo {
   public static void main(String [] args)   {
        Employee e = null;
        try {		
             // 创建反序列化流
             FileInputStream fileIn = new FileInputStream("employee.txt");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             // 读取一个对象
             e = (Employee) in.readObject();
             // 释放资源
             in.close();
             fileIn.close();
        }catch(IOException i) {
             // 捕获其他异常
             i.printStackTrace();
             return;
        }catch(ClassNotFoundException c)  {
        	// 捕获类找不到异常
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
        }
        // 无异常,直接打印输出
        System.out.println("Name: " + e.name);	// zhangsan
        System.out.println("Address: " + e.address); // beiqinglu
        System.out.println("age: " + e.age); // 0
    }
}

对于JVM可以反序列化对象,它必须是能够找到class文件的类。如果找不到该类的class文件,则抛出一个 ClassNotFoundException 异常。

反序列化操作2

**另外,当JVM反序列化对象时,能找到class文件,但是class文件在序列化对象之后发生了修改,那么反序列化操作也会失败,抛出一个InvalidClassException异常。**发生这个异常的原因如下:

  • 该类的序列版本号与从流中读取的类描述符的版本号不匹配
  • 该类包含未知数据类型
  • 该类没有可访问的无参数构造方法

Serializable 接口给需要序列化的类,提供了一个序列版本号。serialVersionUID 该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

如果没有加序列版本号,正常进行序列化和反序列化操作

public class Student implements Serializable {
    private String name;
    private Integer age;
    ...
public class Demo04Test {
    public static void main(String[] args) throws Exception {
        //序列化
        //serialize();
        //反序列化
        deserialize();
        //Student{name='张三', age=20}
    }

    public static void serialize() throws Exception {
        Student stu1 = new Student();
        stu1.setName("张三");
        stu1.setAge(20);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("student.txt")));
        oos.writeObject(stu1);
        oos.close();
    }

    public static void deserialize() throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.txt"));
        Student stu1 = (Student) ois.readObject();
        ois.close();
        System.out.println(stu1);
    }
}

如果对student类进行修改

public class Student implements Serializable {
    private String name;
    private Integer age;
    private Integer sid;//增加一个属性表示学号
    ...

再进行反序列化操作
在这里插入图片描述
异常信息表示:序列化前后的serialVersionUID号码不兼容

  • serialVersionUID是序列化前后的唯一标识
  • 如果没有人为定义 serialVersionUID,编译器会自动声明一个

手动声明serialVersionUID

public class Student implements Serializable {
	private static final Long serialVersionUID = 1L;
    private String name;
    private Integer age;
    ...
### 回答1: Java中的序列化是指将一个对象转换为字节序列的过程,以便于在网络上传输或者将对象保存到磁盘上。在Java中,只有实现了Serializable接口的对象才能被序列化,否则会抛出NotSerializableException异常。序列化可以通过ObjectOutputStream类来实现,反序列化可以通过ObjectInputStream类来实现。序列化Java中广泛应用于分布式系统、缓存、消息队列等场景。 ### 回答2: Java序列化是指将对象转换为可存储或传输的字节序列的过程,可以使得对象的状态在程序结束后仍能够保存。使用Java序列化机制能够方便实现Java对象的持久化,并且在数据传输过程中也可以进行对象的存储和传输,从而可以进行跨平台数据交互。 在Java中,如果一个类需要进行序列化,就需要实现Serializable接口。该接口是一个标记接口,不包含任何方法,只是用来表示这个类可以被序列化。当使用ObjectOutputStream来将某个对象转换成字节序列时,如果该对象所属的类实现了Serializable接口,那么该对象就可以被序列化,否则会抛出NotSerializableException异常。 序列化可以实现多种用途,例如: 1. 持久化:将对象序列化后储存在磁盘上,方便下次读取使用。 2. 分布式:在分布式系统中,对象在不同节点间传输时需要进行序列化和反序列化。 3. 缓存:将对象序列化后储存在缓存中,提高读取速度。 在序列化中也需要注意一些问题,例如: 1. 序列化ID:在序列化时,会对原对象进行哈希处理,生成一个序列化ID。反序列化时,会对这个ID进行比对,如果不一致就会抛出InvalidClassException异常。如果需要保持原有的序列化ID,可以通过声明静态变量serialVersionUID进行指定。 2. 敏感信息:在序列化时,需要注意敏感信息的处理,例如密码、证书等信息不应该被序列化。 3. 序列化版本:在序列化时,需要注意版本的处理。如果对象已经发生了变化,例如增删了某些属性或方法,就需要对版本做出相应的改变,否则会出现兼容性问题。 总之,Java序列化机制为我们提供了一种方便、高效、跨平台的数据交互方式,使用起来相对简单,在实际开发中也非常实用。 ### 回答3: Java序列化是指将一个对象转换成字节流的过程。当一个对象被序列化之后,它的字节流可以被传输到网络或者存储到本地磁盘上,以便于以后的操作。反序列化则是将字节流转换成对象的过程。 序列化Java中的实现方式是通过实现Serializable接口来实现的。在Java中,Serializable接口是一个空接口,仅仅是一个标识接口,用来标记对象可以被序列化和反序列化。如果一个类实现了Serializable接口,那么就可以将该类的对象序列化和反序列化Java序列化机制可以使用ObjectOutputStream类和ObjectInputStream类来实现。ObjectOutputStream类用于将对象序列化成字节流,而ObjectInputStream类用于将字节流反序列化成对象。 序列化的主要用途是将对象在网络中传输以及将对象存储到本地磁盘上。在网络中传输对象时,可以将对象序列化成字节流,然后在网络中传输。接收方可以将收到的字节流反序列化成对象,这样就可以在不同的机器上传递对象。在将对象存储到本地磁盘上时,可以将对象序列化成字节流,然后将字节流写入磁盘,以便以后可以读取该对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值