java中序列化与反序列化

java中序列化与反序列化

1. 序列化与反序列的定义:

    1.序列化:把java对象转化成字节序列的过程
    2.反序列:把字节序列恢复为原java对象的过程

2. 为什么需要序列化与反序列化

   1.当两个进程之间通信时,可以传递各种类型的数据,如:文本,图片,音频,视频,而这些数据都会以二进制形式在网络上传送,那么在两个java进程进行通信时,能否实现进程间对象的传递呢。答案是肯定,如何做到呢,这就需要序列化与反序列化。
   2.一方面,发送方需要把这个java对象转化成字节序列,然后在网络上传送,另一方面,接收方需要把字节序列恢复成原来的java对象。

3. 序列化的意义

    1.一是,可以实现数据的持久化,通过序列化可以把数据持久的保存到磁盘上(通常放在文件中)
    2.二是,利用序列化可以实现远程通信,即在网络上传送字节序列

4. 序列化实现方式

1)jdk中的API
         ObjectOutputStream 输出流
         writeObject(Object obj)对指定的参数对象进行序列化,把得到的字节序列写到一个目标输出流中。
         ObjectInputStream 输入流
         readObject() 从输入流中读取字节序列,再把它们反序列成一个对象返回
2)实现序列化的要求
         只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常
3)实现序列化与反序列化的方法
    假定一个Student类,它的对象需要序列化,可以有如下三种方法:
    方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
         ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
         ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
    方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
         ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
         ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
         (定制的序列化可以序列被static以及transient修饰的变量)
     方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
          (第三种方法不管是否被transient和static修饰,都会被序列化)
          ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
          ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。

5. 序列化注意的事项

1.哪些可以被序列化:对象的类名、Field(包括基本类型、数组、对其他对象的引用)
2.哪些不可以被序列化:static修饰的变量、transient修饰的变量、方法
3.static修饰的变量不能被序列化的原因
     同一个JVM内部只会存在静态变量的一个实例,当然他们是一样的了。也就是说,静态变量并没有被序列化,而只是存在于JVM内部,当反序列化的时候,JVM用的还是这一个实例,难怪他们会是一样的了!

6. transient注意的事项

1.transient只能修饰变量,不能修饰方法和类,本地变量不能被transient关键字修饰
2.一旦被transient修饰,该变量就不是持久化的一部分,该变量内容在序列化后将无法获得,也可以认为,在将持久化的对象反序列化后,被transient修饰的变量将按照普通的类成员变量一样被初始化

7. 代码

方法一:
public class Person implements Serializable {
    private String name;
    private int age;
    private transient Date date = new Date();
    private static int staticValue = 11;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public static int getStaticValue() {
        return staticValue;
    }

    public static void setStaticValue(int staticValue) {
        Person.staticValue = staticValue;
    }

    @Override
    public String toString() {
        return String.format("My name is %s, and I'm %d years old. %tc,%d",
                name, age,date,staticValue);
    }
}


public class SerializableDemo {
    //序列化与饭序列化
        /**
         * 1.序列化与反序列的定义:
         *   序列化:把java对象转化成字节序列的过程
         *   反序列:把字节序列恢复为原java对象的过程
         * 2.为什么需要序列化与反序列化
         *   当两个进程之间通信时,可以传递各种类型的数据,如:文本,图片,音频,视频,而这些数据都会以二进制形式在网络上传送,那么在两个java进程进行通信时,能否实现进程间对象的传递呢。答案是肯定,如何做到呢,这就需要序列化与反序列化。
         *   一方面,发送方需要把这个java对象转化成字节序列,然后在网络上传送,另一方面,接收方需要把字节序列恢复成原来的java对象。
         * 3.序列化的意义
         *   一是,可以实现数据的持久化,通过序列化可以把数据持久的保存到磁盘上(通常放在文件中)
         *   二是,利用序列化可以实现远程通信,即在网络上传送字节序列
         * 4.序列化实现方式
         *   1)jdk中的API
         *      ObjectOutputStream 输出流
         *          writeObject(Object obj)对指定的参数对象进行序列化,把得到的字节序列写到一个目标输出流中。
         *      ObjectInputStream 输入流
         *          readObject() 从输入流中读取字节序列,再把它们反序列成一个对象返回
         *   2)实现序列化的要求
         *       只有实现了Serializable或Externalizable接口的类的对象才能被序列化,否则抛出异常
         *   3)实现序列化与反序列化的方法
         *        假定一个Student类,它的对象需要序列化,可以有如下三种方法:
         *        方法一:若Student类仅仅实现了Serializable接口,则可以按照以下方式进行序列化和反序列化
         *        ObjectOutputStream采用默认的序列化方式,对Student对象的非transient的实例变量进行序列化。
         *        ObjcetInputStream采用默认的反序列化方式,对对Student对象的非transient的实例变量进行反序列化。
         *        方法二:若Student类仅仅实现了Serializable接口,并且还定义了readObject(ObjectInputStream in)和writeObject(ObjectOutputSteam out),则采用以下方式进行序列化与反序列化。
         *        ObjectOutputStream调用Student对象的writeObject(ObjectOutputStream out)的方法进行序列化。
         *        ObjectInputStream会调用Student对象的readObject(ObjectInputStream in)的方法进行反序列化。
         *        (定制的序列化可以序列被static以及transient修饰的变量)
         *        方法三:若Student类实现了Externalnalizable接口,且Student类必须实现readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,则按照以下方式进行序列化与反序列化。
         *        (第三种方法不管是否被transient和static修饰,都会被序列化)
         *        ObjectOutputStream调用Student对象的writeExternal(ObjectOutput out))的方法进行序列化。
         *        ObjectInputStream会调用Student对象的readExternal(ObjectInput in)的方法进行反序列化。
         * 5.序列化注意的事项
         *   哪些可以被序列化:对象的类名、Field(包括基本类型、数组、对其他对象的引用)
         *   哪些不可以被序列化:static修饰的变量、transient修饰的变量、方法
         *   static修饰的变量不能被序列化的原因
         *   同一个JVM内部只会存在静态变量的一个实例,当然他们是一样的了。也就是说,静态变量并没有被序列化,而只是存在于JVM内部,当反序列化的时候,JVM用的还是这一个实例,难怪他们会是一样的了!
         * 6.transient注意的事项
         *    transient只能修饰变量,不能修饰方法和类,本地变量不能被transient关键字修饰
         *    一旦被transient修饰,该变量就不是持久化的一部分,该变量内容在序列化后将无法获得,也可以认为,在将持久化的对象反序列化后,被transient修饰的变量将按照普通的类成员变量一样被初始化
         */
    public static void main(String[] args) throws Exception {
    Person person = new Person("peron",10);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(
                new File("0xjh000")));
        out.writeObject(person);
        person.setAge(111);
        person.setStaticValue(3);
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(
                new File("0xjh000")));
        Person person1 = (Person) in.readObject();
        System.out.println(person1);
    }
}
方法二:
public class Person1 implements Serializable{
    private static String name;
    private transient int age;

    public Person1() {
    }

    public Person1(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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;
    }
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        //将name实例变量值反转后写入二进制流
        out.writeObject(new StringBuffer(name).reverse());
        out.writeInt(age);
        out.close();
    }
    private void readObject(java.io.ObjectInputStream in) throws Exception{
        //将读取的字符串反转后赋给name变量
        this.name = ((StringBuffer)in.readObject()).reverse().toString();
        this.age = in.readInt();
        in.close();
    }

    public static void main(String[] args) throws Exception {
        Person1 pre = new Person1("WSDFG",10);
        pre.writeObject(new ObjectOutputStream(new FileOutputStream(new File("s"))));
        Person1.name="weffg";
        Person1 p = new Person1();
        p.readObject(new ObjectInputStream(new FileInputStream(new File("s"))));
        System.out.println(p.age+"  "+p.name);
    }
}
方法三:
public class ExternalizableTest implements Externalizable{

    private static String content = "哈哈~我将会被序列化,不管我是是否被transient和static关键字修饰";

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(content);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        content = (String) in.readObject();
    }

    public static void main(String[] args) throws Exception {
        ExternalizableTest et = new ExternalizableTest();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream(
                new File("ext0000")));
        out.writeObject(et);

        ExternalizableTest.content="ss";

        ObjectInput in = new ObjectInputStream(new FileInputStream(new File(
                "ext0000")));
        ExternalizableTest et1 = (ExternalizableTest) in.readObject();
        System.out.println(et1.content);

        out.close();
        in.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java序列化是将对象转换为字节流的过程,以便将其存储在磁盘上或通过网络传输。而反序列化则是将字节流转换回对象的过程。 下面是一个示例,演示如何序列化反序列化一个Java对象: ```java import java.io.*; public class SerializationExample { public static void main(String[] args) { // 创建一个Person对象 Person person = new Person("Alice", 30); try { // 将Person对象序列化到文件 FileOutputStream fileOut = new FileOutputStream("person.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(person); out.close(); fileOut.close(); System.out.println("Person对象已经序列化到person.ser文件"); } catch (IOException e) { e.printStackTrace(); } try { // 将Person对象从文件反序列化出来 FileInputStream fileIn = new FileInputStream("person.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); Person serializedPerson = (Person) in.readObject(); in.close(); fileIn.close(); System.out.println("从person.ser文件反序列化出的Person对象:"); System.out.println("姓名:" + serializedPerson.getName()); System.out.println("年龄:" + serializedPerson.getAge()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class Person implements Serializable { private static final long serialVersionUID = 1L; 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; } } ``` 运行该程序,它会将一个Person对象序列化到文件person.ser,并从该文件反序列化出Person对象,并将其打印出来。 需要注意的是,要将一个对象序列化,该对象的类必须实现java.io.Serializable接口。否则,将会抛出NotSerializableException异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值