美文网首页Java 杂谈
Java中的序列化

Java中的序列化

作者: zhang5788 | 来源:发表于2018-08-12 18:46 被阅读0次

序列化

什么是序列化?

当你创建对象时,只有你需要,它就会一直存在,但是在程序终止时,无论如何他都不会在内存中存活。尽管这是有意义的,但是如果能将一个对象剥离到硬盘中,进行持久化存储,这也是很有意义的。Java提供了这么一个功能,就是序列化。

如何序列化?

在Java中,提供了两个接口来进行序列化操作。

1. Serializable 接口

这个接口是java中的一个标记接口,实现这个接口的类会被java识别为可以被序列化的类。

public class A implements Serializable {
    private String a;
    private String b;
    private int c;

    A(String a, String b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
    @Override
    public String toString()  {
        return a + ", "+ b + ", " + c;
    }
}

public static void main(String[] args) throws Exception {
        A a = new A("1", "2", 3);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/zhangt/Desktop/A.out"));
        out.writeObject(a);
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/zhangt/Desktop/A.out"));
        A a1 = (A)in.readObject();
        System.out.println(a1);
}

输出结果为:
1, 2, 3
这代表我们从文件中读取的类就是我们实例化的那个类。

2. Externalizable 接口

Externalizable 接口是Seriazable 接口的一个子接口。这个接口中定义了两个方法:

public interface Externalizable extends java.io.Serializable {
   void writeExternal(ObjectOutput out) throws IOException;
   void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

这个接口虽然是Serializable的子接口,但是并不是一个标记性质的接口。实现该接口的类必须强制实现这两个方法:

  • wirteExternal(ObjectOutput out)
    该方法中,用来控制哪些字段可以被序列化。
  • readExternal(ObjectInput in)
    该方法中,用来读取哪些字段可以被反序列化。
    我们改造一下上面的类A
public class A implements Externalizable {
    private String a;
    private String b;
    private int c;

    public A(String a, String b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public String toString()  {
        return a + ", "+ b + ", " + c;
    }


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

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

public static void main(String[] args) throws Exception {
        A a = new A("1", "2", 3);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/zhangt/Desktop/A.out"));
        out.writeObject(a);
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/zhangt/Desktop/A.out"));
        A a1 = (A)in.readObject();
        System.out.println(a1);
}

输出结果为:

Exception in thread "main" java.io.InvalidClassException: ioPackage.A; no valid constructor
    at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:157)
    at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:862)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2041)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1571)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
    at ioPackage.Client.main(Client.java:14)

在相关资料中,查到:

Externalizable 接口标识的类,在进行反序列化时,会调用类的默认构造器。

由于我们自定义了A的构造器,导致默认的构造器并没有被生成,于是我们在A中添加一个默认的构造器。运行, 结果为:
1, 2, 0
因为,我们并没有对int c 进行序列化,反序列化的操作,导致c被初始化为默认值0。

是不是想要对序列化的类进行字段限制,就只能实现Externalizable 接口,实现方法呢? 并不是的,其实Serializable 接口也可以控制字段的序列化。

3.Serializable的序列化控制

transient 关键字就是用来控制Serializable的字段的.
我们修改类A:

 private String a;
    transient private String b;
    private int c;


    public A(String a, String b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public String toString()  {
        return a + ", "+ b + ", " + c;
    }

运行结果为:
1, null, 3
字段String b 就被默认为null

这里需要提及的一点是:

String 类型的默认值是null , 而不是字符串"null", 但是,在反序列化的过程中,被限制的String 类型的字段值是字符串"null".

序列化可能会遇到的问题

1. 如果我反序列化相同的类多次,它们的在java中会是同一个对象么?

由于反序列的过程就是将一个类读入内存的过程,如果多次反序列化,肯定是开辟多个内存地址.这就表示在Java中,它们是不同的两个对象.
但是,也存在例外.如果你的对象是由同一个流读进来的对象,那么它们就是相同的.

ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/zhangt/Desktop/A.out"));
        A a1 = (A)in.readObject();
        in.close();
        ObjectInputStream in2 = new ObjectInputStream(new FileInputStream("/Users/zhangt/Desktop/A.out"));
        A a2 = (A)in2.readObject();
        in2.close();

a1a2的地址是不同的.

A a = new A("1", "2", 3);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/zhangt/Desktop/A.out"));
        out.writeObject(a);
        out.writeObject(a); // 输出两次
        out.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/zhangt/Desktop/A.out"));
        A a1 = (A)in.readObject();
        A a2 = (A)in.readObject();
        System.out.println(a1);
        System.out.println(a2);

a1a2 的地址是相同的.

2. 如果序列化的类中包含其他类的对象,多次反序列化后,第三方对象会在内存中存在一份还是多份?

如果在序列化前,多个序列化类指向的对象是同一个对象,那么反序列化后指向的还是同一个对象.反序列化的结果的对象网和序列化之前是相同的.

相关文章

  • transient关键字

    Java中的序列化 在讨论transient之前,有必要先搞清楚Java中序列化的含义: Java中对象的序列化指...

  • JAVA反序列化漏洞

    目录 反序列化漏洞序列化和反序列化JAVA WEB中的序列化和反序列化对象序列化和反序列范例JAVA中执行系统命令...

  • 序列化(java Serializeable、json、prot

    java序列化 序列化:将对象写入到IO流中反序列化:从IO流中恢复对象意义:序列化机制允许将实现序列化的Java...

  • 总结

    java基础 Java中多态的理解 反射 Java序列化与反序列化 Volatile和Synchronized e...

  • ArrayList的elementData为什么要用transi

    先解释下Java中的对象序列化 在讨论transient之前,有必要先搞清楚Java中序列化的含义;Java中对象...

  • Java-序列化-反序列化

    Thanks Java基础学习总结——Java对象的序列化和反序列化java序列化反序列化原理Java 序列化的高...

  • Java序列和反序列,看这一篇就够了

    前言 java的序列化和反序列化内容是java学习的基础之一,java的序列化常见于网络中的对象传输以及内存对象持...

  • java序列化那些事儿

    java序列化作用 在说java序列化的作用之前,先说下什么是java序列化吧。java序列化是指把java对象转...

  • 详解Java序列化机制

    序列化有什么意义 首先我们先看看,java中的序列化,在java语言中实例对象想要序列化传输,需要实现Serial...

  • Java序列化

    Java序列化的几种方式以及序列化的作用 Java基础学习总结——Java对象的序列化和反序列化

网友评论

    本文标题:Java中的序列化

    本文链接:https://www.haomeiwen.com/subject/btzsbftx.html