jvm在java中对标记接口做了啥

Posted

技术标签:

【中文标题】jvm在java中对标记接口做了啥【英文标题】:what jvm do with marker interface in javajvm在java中对标记接口做了什么 【发布时间】:2014-10-01 12:01:05 【问题描述】:

正如问题所说,JVM 对实现标记接口的类给予了额外的处理。 例如,我使用 Serializable 对其进行了测试,如下所示:

导入 java.io.*;

public class SerialazationDemo 
    public static void main(String[] args) 
        //serialized object
/*      Employee e = new Employee();
        e.name = "Reyan Ali";
        e.address = "Phokka Kuan, Ambehta Peer";
        e.SSN = 11122333;
        e.number = 101;
        try 
            FileOutputStream fileOut = new FileOutputStream("E:\\temp\\employee.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(e);
            out.close();
            fileOut.close();
            System.out.printf("Serialized data is saved in /tmp/employee.ser");
         catch (IOException i) 
            i.printStackTrace();
        */

        //deserialized object
         Employee e = null;
          try
          
             FileInputStream fileIn = new FileInputStream("E:\\temp\\employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (Employee) in.readObject();
             in.close();
             fileIn.close();
          catch(IOException i)
          
             i.printStackTrace();
             return;
          catch(ClassNotFoundException c)
          
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
          
          System.out.println("Deserialized Employee...");
          System.out.println("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
    


class Employee 
    public String name;
    public String address;
    public transient int SSN;
    public int number;

    public void mailCheck() 
        System.out.println("Mailing a check to " + name + " " + address);
    

我发现 jvm 给出了 java.io.NotSerializableException 异常但是 FILES 是在给定路径上创建的,类似的反序列化异常。那么为什么JVM要求它被序列化,它可以直接允许创建一个序列化。?

【问题讨论】:

您似乎同时问了三个问题:JVM 对标记接口做了什么?为什么创建文件?为什么不是一切Serializable? 【参考方案1】:

问题说 JVM 对实现 Marker 接口的类给予了额外的处理

该问题的正确答案是什么都没有。但这可能需要说明,因为提问者可能使用的术语不准确。

JRE 在适当的地方特别对待它们。此操作位于 Java 类库中,而不是 JVM 中。例如:

Object.clone() 测试对象实现了Cloneable. ObjectOutputStream.writeObject() 测试正在编写的对象实现 Serializable. rmic 和部分 RMI 运行时测试远程对象实现远程接口,这意味着接口扩展 Remote.

这与 JVM 本身无关。

我发现 jvm 给出的异常为 java.io.NotSerializableException

不,你没有。你发现ObjectOutputStream.writeObject() 抛出了异常。这不是一回事。

但文件是在给定路径上创建的

该文件由new FileOutputStream(...), 创建,在您遇到异常之前已经执行。

那么为什么JVM要求它被序列化,它可以直接允许创建一个序列化。?

它没有。往上看。但是ObjectOutputStream.writeObject() 确实如此,而且它之所以这样做是因为制作所有东西Serializable 有许多缺点,在你提出建议之前需要考虑这些缺点。例如,考虑您不希望的可序列化密码字段的安全风险。

【讨论】:

【参考方案2】:

您需要扩展Serializable(或Externalizable)的原因是为了确保您只对设计用于序列化的类进行序列化。你当然不想序列化不是为它设计的类,因为那样它们的格式会很脆弱;对类的最小更改会破坏您的反序列化。

有人可能会争辩说,同样的脆弱性也适用于标记为Serializable 的类,但在将类标记为Serializable 时,您应该考虑串行形式的稳定性(或者像 Guava 那样明确否认任何稳定性)。

【讨论】:

【参考方案3】:

如果对象不是Serializable,则无法使用ObjectOutputStrem 保存其状态。

必须创建文件,因为这是使用FileInputStream 完成的,并且一旦您关闭流,就会有一个新文件。但是如果尝试检查文件的内容,它应该是空的,因为不可序列化状态的状态不会被保存。

【讨论】:

【参考方案4】:

什么是标记接口?

当一个接口被提供为一个标记接口时,它被称为标记接口。 由 java 解释器处理以标记一个类,以便它可以提供 在运行时对它的特殊行为,它们没有任何方法 声明

标记接口只是将一个类标记为特定类型。

为什么需要标记接口?

Marker 接口用作标记,将消息通知给 java 编译器,以便它可以向类添加特殊行为 实现它。所以如果JVM看到一个类是可序列化的,它会做一些 对其进行特殊操作

JVM 对序列化接口做了什么?

当一个类实现可序列化的接口时,它向 JVM 保证 这个类可以提供一个特殊的 运行时的行为(序列化/反序列化)。

因此,当您尝试序列化对象时,JVM 想要确认该类型的对象类是否已签订合同(实现序列化接口)以在运行时显示此特殊行为(要序列化/反序列化)。如果它有实现后,JVM 可以确保它可以进一步进行序列化,否则它会抛出异常,表明您正在尝试序列化一个不同意准备好进行序列化或反序列化的条款和条件的对象。

【讨论】:

您不能为Serializable,CloneableRemote, 使用注释,毫无疑问还有很多其他的。 @EJP :我刚刚说过标记接口。 我提到的三个都是marker接口。对它们的需求并未消除。您需要限定您的评论。 @EJP:我将从答案中删除该注释:) 好主意。无论如何,这无关紧要,也很可疑。除非已经有一个注释处理框架,否则我没有发现注释更方便。编写检测注释的代码是instanceof 的 10 倍。

以上是关于jvm在java中对标记接口做了啥的主要内容,如果未能解决你的问题,请参考以下文章

Java 标记接口

什么是Java Marker Interface(标记接口)

什么是Java Marker Interface(标记接口)

什么是Java Marker Interface(标记接口)

为什么这些java接口没有抽象方法?浅谈Java标记接口

内功心法 -- Java标记接口