美文网首页
Externalizable序列化与反序列化

Externalizable序列化与反序列化

作者: 竹鼠不要中暑 | 来源:发表于2019-02-24 17:12 被阅读9次

    java.io.Externalizable接口的主要目标是促进自定义序列化和反序列化。在任务卡中已经学习了Serializable接口的序列化与反序列化的用法,下面再来看看Externalizable的用法。

    用法

    任何实现Externalizable接口的类都应该实现writeExternal()readExternal()方法。

    • Animal
    import java.io.Externalizable;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectOutput;
    
    public class Animal implements Externalizable {
        private static final long serialVersionUID = 1L;
        private String name;
        private int age;
    
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return this.age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeUTF(name);
            out.writeInt(age);
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            this.name = in.readUTF();
            this.age = in.readInt();
        }
    }
    

    如上,写了一个Animal类实现了Externalizable接口,serialVersionUID设为默认的1L。有一个问题需注意,当实现序列化接口时,类中须有一个无参的构造函数。Animal类中没有呢定义构造函数,会默认一个无参的构造函数。而当你定义的类含有有参数的构造函数时,你就要再定义一个无参的构造函数了。

    • 测试 Test
    import java.io.*;
    
    public class Test {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            Animal animal = new Animal();
            animal.setName("小白");
            animal.setAge(3);
    
    //        序列化
            FileOutputStream fileOutputStream = new FileOutputStream("./Animal.txt"); //创建文件字节输出流对象
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            animal.writeExternal(objectOutputStream);
            // 关闭资源,objectOutputStream.close()内部已经将fileOutputStream对象资源释放了
            objectOutputStream.close();
    
    //         反序列化
            FileInputStream fileInputStream = new FileInputStream("./Animal.txt"); // 创建文件字节输入流对象
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    
            Animal animal1 = new Animal();
            animal1.readExternal(objectInputStream);
            // 关闭资源
            objectInputStream.close();
    
            System.out.println("name: " + animal1.getName());
            System.out.println("age: " + animal1.getAge());
        }
    }
    

    输出:

    name: 小白
    age: 3
    

    继承

    写一个Dog类继承Animal,并实现Externalizable接口:

    import java.io.Externalizable;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectOutput;
    
    public class Dog extends Animal implements Externalizable {
        private static final long serialVersionUID = 1L;
        private double height;
        private String breed;
    
        public double getHeight() {
            return this.height;
        }
    
        public void setHeight(double height) {
            this.height = height;
        }
    
        public String getBreed() {
            return this.breed;
        }
    
        public void setBreed(String breed) {
            this.breed = breed;
        }
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            super.writeExternal(out);
            out.writeDouble(height);
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            super.readExternal(in);
            this.height = in.readDouble();
        }
    }
    
    

    有两点需要注意:

    • Dog的在序列化程序方法中调用了super.writeExternal(out)super.readExternal(in)来保存/恢复父类字段;
    • Dog的breed属性没有被序列化

    测试Test:

    import java.io.*;
    
    public class Test {
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            Dog dog = new Dog();
            dog.setName("小白");
            dog.setAge(3);
            dog.setBreed("柯基");
            dog.setHeight(18);
    
    //        序列化
            FileOutputStream fileOutputStream = new FileOutputStream("./dog.txt"); //创建文件字节输出流对象
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
            dog.writeExternal(objectOutputStream);
            // 关闭资源,objectOutputStream.close()内部已经将fileOutputStream对象资源释放了
            objectOutputStream.close();
    
    //         反序列化
            FileInputStream fileInputStream = new FileInputStream("./dog.txt"); // 创建文件字节输入流对象
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
    
            Dog dog1 = new Dog();
            dog1.readExternal(objectInputStream);
            // 关闭资源
            objectInputStream.close();
    
            System.out.println("name: " + dog1.getName());
            System.out.println("age: " + dog1.getAge());
            System.out.println("height: " + dog1.getHeight());
            System.out.println("breed: " + dog1.getBreed());
        }
    }
    

    结果:

    name: 小白
    age: 3
    height: 18.0
    breed: null
    

    因为Dog类的breed属性没有被序列化,因此dog1的breednull

    Externalizable与Serializable的区别

    • 序列化责任
      当类实现java.io.Serializable接口时,JVM完全负责序列化类实例。在Externalizable的情况下,程序员应该负责整个序列化和反序列化过程(因为是自定义的,回想writeExternalreadExternal)。
    • 执行效率
      Serializable所有对象由Java统一保存,性能较低;Externalizable开发人员决定哪个对象保存,可能使得速度提升。
    • 保存信息
      Serializable保存时占用空间大;Externalizable部分存储,可能使得空间减少。
    • 阅读顺序
      使用Externalizable时,必须按照写入(writeExternal)时的确切顺序读取(readExternal)所有字段状态。否则,会抛出 java.io.EOFException 。Serializable接口没有这个要求。
    • 自定义序列化
      我们可以通过使用transient关键字标记字段来使用Serializable接口实现自定义序列化。JVM不会序列化特定字段,但它会将字段添加到具有默认值的文件存储。因此自定义序列化时使用Externalizable更好。

    相关文章

      网友评论

          本文标题:Externalizable序列化与反序列化

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