Java对象的序列化和反序列化

本文介绍了Java中对象的序列化与反序列化的基本概念及其应用,详细讲解了如何使用java.io.ObjectOutputStream和java.io.ObjectInputStream进行对象的序列化与反序列化操作,并通过示例展示了这一过程及其实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java对象的序列化和反序列化

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。

序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。

对象的序列化主要有两种用途:
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

对象序列化

1、序列化API

  java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。只有实现了Serializable和Externalizable接口的类的对象才能被序列化。

  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

2、示例代码:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/*
 * 对象的序列化与反序列化
 */
public class ObjectStreamTest {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        // TODO Auto-generated method stub
        Employee harry=new Employee("Harry Hacker", "女", 50000, 1989, 5, 6);
        Manager carl=new Manager("Carl Cracker", "男", 80000, 1987, 12, 15);
        carl.setSecretary(harry);
        carl.setBonus(500);

        Manager tony=new Manager("Tony Tester", "男", 40000, 1990, 3, 15);
        tony.setBonus(1000);
        tony.setSecretary(harry);

        Employee[] staff=new Employee[3];
        staff[0]=carl;
        staff[1]=harry;
        staff[2]=tony;

        // 序列化前
        for(Employee e:staff){
            System.out.println(e.toString());
        }
        System.out.println("\n\n");


        try(ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("employee.dat")))
        {
            out.writeObject(staff);
        }

        Employee[] newStaff=null;
        try(ObjectInputStream in=new ObjectInputStream(new FileInputStream("employee.dat")))
        {

            newStaff=(Employee[]) in.readObject();
            newStaff[1].raiseSalary(10);            
        }

        // 反序列化后
        for(Employee e:newStaff){
            System.out.println(e.toString());
        }
    }
}

其中Employee类和Manager 类定义如下:

Employee类

import java.io.Serializable;
import java.sql.Date;

public class Employee implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String name;
    private String gender;
    private double salary;
    private Date hireDay;

    public Employee(String n,String g,double s,int y,int m,int d){
        this.name=n;
        this.gender=g;
        this.salary=s;
        @SuppressWarnings("deprecation")
        Date day=new Date(y-1900, m-1, d);
        this.hireDay=day;
    }
    public String getName(){
        return name;
    }
    public double getSalary(){
        return salary;
    }
    public String getGender(){
        return gender;
    }
    public Date getHireDay(){
        return hireDay;
    }
    public void raiseSalary(double byPercent){
        double raise=salary*byPercent/100;
        salary+=raise;
    }

    public String toString(){
        String str=name+":"+gender+", "+salary+", "+hireDay.toString();
        return str;
    }
}

Manager 类

public class Manager extends Employee {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private Employee secretary;
    private double bonus;

    public Manager(String n,String g,double s,int y,int m,int d){
        super(n, g, s, y, m, d);
        bonus=0;
        secretary=null;
    }

    public double getSalary(){
        double baseSalary=super.getSalary();
        return baseSalary+bonus;
    }
    public void setBonus(double b){
        bonus=b;
    }
    public void setSecretary(Employee em){
        this.secretary=em;
    }
    public Employee getSecretary(){
        return secretary;
    }

    public String toString(){
        String str=super.toString();
        String str1=secretary.getName();
        return str+" 秘书:"+str1;
    }
}
对象序列化用途之一—-克隆

序列化机制有一个很有趣的用法:提供了一种克隆对象的简便途径,只要对应的类是可序列化的即可。其做法很简单:直接将对象序列化到输出流中,然后将其读回。这样产生的新对象是对现有对象的一个深拷贝。在此过程中,我们不必将对象写入到一个文件中,因为可以用ByteArrayOutputStream将数据保存到字节数组中。

下面的示例代码展现了这一过程:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.GregorianCalendar;

public class SerialCloneTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Person dandan=new Person("DanDan", "female", 1991, 8, 29);
        Person jiayan=(Person)dandan.clone();
        jiayan.setName("JiaYan");

        System.out.println(dandan);
        System.out.println(jiayan);
    }

}

class SerialCloneable implements Cloneable,Serializable
{

    private static final long serialVersionUID = 1L;

    public Object clone(){
        try{
            // save the object to a byte array
            ByteArrayOutputStream bout=new ByteArrayOutputStream();
            ObjectOutputStream out=new ObjectOutputStream(bout);
            out.writeObject(this);
            out.close();

            // read a clone of the object from the byte array
            ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());
            ObjectInputStream in=new ObjectInputStream(bin);
            Object ret=in.readObject();
            in.close();
            return ret;
        }catch(Exception e){
            return null;
        }
    }
}

/**
    要被克隆的对象需要继承SerialCloneable类
*/
class Person extends SerialCloneable
{

    private static final long serialVersionUID = 1L;
    private String name;
    private String gender;
    private Date birthDay;

    public Person(String n,String g,int year,int month,int day)
    {
        name=n;
        gender=g;
        GregorianCalendar calendar=new GregorianCalendar(year,month-1,day);
        birthDay=calendar.getTime();
    }

    public String getName(){
        return name;
    }
    public String getGender(){
        return gender;
    }
    public Date getBirthDay(){
        return birthDay;
    }
    public void setName(String newName){
        name=newName;
    }
    public String toString()
    {
        return getClass().getName()
                +"[name="+name
                +",gender="+gender
                +"birthDay="+birthDay
                +"]";
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值