java Serializable接口没有功能,为啥会影响“writeObject”/“readObject”

Posted

技术标签:

【中文标题】java Serializable接口没有功能,为啥会影响“writeObject”/“readObject”【英文标题】:java Serializable interface has no function, why it affects "writeObject"/"readObject"java Serializable接口没有功能,为什么会影响“writeObject”/“readObject” 【发布时间】:2019-04-25 07:54:24 【问题描述】:

我检查了界面

Serializable

没有函数定义,但当我定义时

private void readObject(ObjectOutputStream oos)
    System.out.println("readObject!!");

private void writeObject(ObjectOutputStream oos)
    System.out.println("writeObject!!");

类中的函数,它们在对象被序列化时被调用。

这对我来说很奇怪,如果接口定义了这两个函数,那么我应该重写它们以确保它们被调用。

但是在 Serializable 中,如果我定义自己的“writeObject”/“readObject”,编译器如何生成代码,它们会在序列化时被调用?

我尝试添加

@Override

在两个函数上加注解,编译器报错。

那么它是如何工作的,你能帮忙解释一下吗?

非常感谢!

【问题讨论】:

它本质上是一个肮脏的黑客。序列化机制通过反射搜索这些方法。 编译器不知道方法和接口之间是否存在联系,因此如果名称/签名不正确,则无济于事。相反,库在运行时查找该方法,如果找到,它将调用它们。在 java 8 中,这些方法可以使用 default 实现,但是这在 Java 1 中不可用。 【参考方案1】:

java.io.Serializable 是一个函数式接口,这意味着它没有在其中定义任何方法。如果您真的想确保没有人会尝试修改您的覆盖方法,则会放置 @Override 注释。您在@Override 上遇到编译器错误的原因是 Serializable 中没有这样的方法,但是您可以在 ObjectInputStream 和 ObjectOutputStream (分别用作低级类 FileInputStream 和 FileOutputStream )中找到它们。 如果你真的想对一个列表进行序列化,你可以这样做:

package Chaper8.IO;

import java.io.*;

import java.util.*;

public class Serialization_Deserialization 

public static void main(String [] args)

    /*
     *  try-catch with resources, JVM makes sure to close the resources after you've finished using it
     * much easier than using finally and getting an exception for each resource closed
     * 
     */
    try(FileOutputStream out = new FileOutputStream("C:\\Users\\Andrei\\Desktop\\Exemple\\worker.txt");
        ObjectOutputStream oos = new ObjectOutputStream(out);

        FileInputStream in = new FileInputStream("C:\\Users\\Andrei\\Desktop\\Exemple\\worker.txt");
        ObjectInputStream ois = new ObjectInputStream(in);)

        //instances of the Worker class
        Worker w1 = new Worker("Worker1", 123456 , 2000.5);
        Worker w2 = new Worker("Worker2", 765436, 1500.15);
        Worker w3 = new Worker("Worker3", 364582, 1700.45);
        Worker w4 = new Worker("Worker4", 878234, 2100.34);
        ArrayList<Worker> list = new ArrayList<>();

        //just adding the persons in the list
        list.add(w1);
        list.add(w2);
        list.add(w3);
        list.add(w4);


        System.out.println("Doing serialization");
        oos.writeObject(list);

        System.out.println("Doing deserialization");
        ois.readObject();

    catch(IOException | ClassNotFoundException e)
            e.printStackTrace();
    

 

Worker.java

/*
 *  Worker class, basic type with variables, constructor, and toString() overridden
 *  Here I have implemented Serializable for the reason that I need to make sure that
 *  I will serialize the object within the class
 *
 *  Note that I used transient for id. transient is a special keyword which makes sure 
 * that id will not be serialized, used for security reasons.
 * 
 *  serialVersionUID is another variable which is used during deserialization 
 * to verify that the sender and receiver of a serialized object have loaded 
 * classes for that object that are compatible with respect to serialization. 
 *  Throws InvalidClassException if the object has a different serialVersionUID
 * than that of the corresponding sender's class.
 *  
 */

import java.io.*;
class Worker implements Serializable

private static final long serialVersionUID = 1L;
private String name;
private transient int id;
private double wage;

public Worker(String name, int id, double wage)
    this.name = name;
    this.id = id;
    this.wage = wage;

public String toString()
    return "Person with name " +
    name + " and with id " +
    id + " has a salary of " + wage + "$";
    

【讨论】:

Serializable 不是“功能接口”。该术语用于描述只有一个抽象方法的接口(并且就像它只是一个函数一样使用)。您正在寻找的短语是“标记界面”。还有Cloneable,谢天谢地,其他人很少。 同意@TomHawtin-tackline 的评论,说明Serializable 是一个功能接口的答案怎么可能是一个有效的答案。 我还应该指出,尽管在ObjectInputStream/ObjectOutputStream 中有称为readObject/writeObject 的方法,但这些方法与自定义readObject/writeObject 具有不同的签名,并且是没有直接关系。

以上是关于java Serializable接口没有功能,为啥会影响“writeObject”/“readObject”的主要内容,如果未能解决你的问题,请参考以下文章

java.io.Serializable

Serializable接口

请问Serializable序列化的作用,到底是啥?

Java 标记接口

java_序列化

Java 之 序列化接口