【问题标题】:Is this possible to write a Marker interface这可以写一个Marker接口吗
【发布时间】:2017-01-16 14:19:37
【问题描述】:

我已经完成了以下教程:

http://www.javaworld.com/community/node/2915

看完上面的文章,我觉得,不可能 写一个 Marker 接口,因为,你怎么能指示编译器,那个,什么标签, 它嵌入到标记接口的 .class 文件中。

如果我错了,请纠正我。 干杯:)

【问题讨论】:

  • 什么?抱歉,但我无法解析“你如何指示编译器,thta,什么标签,它嵌入到你的类的 .class 文件中。”你能换个说法吗?
  • 是的,让我的问题更清楚。
  • 还是不太清楚:这和序列化有什么关系?您只需询问标记接口,这不一定与序列化有关(这只是标记接口的一种用途)。另外:您所说的“标签”是什么? Java 中没有这样的东西。
  • 这里的标签是十六进制代码AC ED,它被添加到实现Serializable接口的那个类的.class文件中。因此,JVM 以一种特殊的方式处理这个类文件(可能是一些繁重的资源分配工作),因为这个类的实例可能被序列化。对于普通类,它添加了 CA FE 十六进制位。
  • 据我了解这篇文章,AC ED 被添加到实例的序列化形式中,而不是 .class 文件中。每个类文件都应该以 0xCAFEBABE 开头:java.sun.com/docs/books/jvms/second_edition/html/…

标签: java serialization


【解决方案1】:

这里的标签是十六进制代码AC ED,它被添加到实现Serializable接口的那个类的.class文件中。所以,JVM 以一种特殊的方式处理这个类文件(可能是一些繁重的资源分配工作),因为这个类的实例可能被序列化。对于普通类,它添加了 CA FE hex。

啊哈!!我理解你的困惑。

  • CA FE 字节码文件的幻数;即编译类时获得的文件。任何类的字节码文件都有这个幻数,无论它是可序列化的还是不可序列化的。

  • AC ED 是一个序列化的 Java 对象文件的幻数;即您序列化某个可序列化类的实例的文件。

您正在混淆两个不同的概念(类和实例)及其各自的表示。

所以你的问题的答案是......当然你可以编写自己的标记界面!对于实现标记接口的类,编译器没有什么特别之处。

但是,不可能在纯 Java 中复制 Java 对象反序列化的实现。对象反序列化使用后门(Unsafe.allocateInstance 方法)在不调用构造函数的情况下创建对象。 AFAIK,无法从普通 Java 代码调用此方法。 (即使可以,也不应该……)

【讨论】:

  • 感谢斯蒂芬先生纠正我。但是,这又引发了一种混乱。如果 Serializable 是一个很普通的接口(但是 Marker,没有成员,没有声明)。那么,为什么一个类需要实现 Serializable 来编写一个对象。 jvm 在序列化或反序列化之前是否会检查 (x instanceof Serializable) 之类的内容。
  • @rits - 不是 JVM。源代码位于docjar.com/html/api/java/io/ObjectOutputStream.java.html - 请参见第 1166 行。
【解决方案2】:

当然你可以写一个标记界面。标记接口通常只是一个没有任何方法的接口(因此任何类都可以实现它)。

您似乎认为标记接口具有一些神奇的属性,它们可以自己做某事。事实并非如此。相反,一些 other 代码可以对某个对象上存在的标记接口做出反应,并在类实现它时采取不同的行为。但是标记界面本身什么都不做

【讨论】:

  • 所以标记接口只是一个没有方法声明的简单接口。而且,如果一个类实现了 Marker 接口(Serializable)或任何普通接口(带有方法声明),类文件中不会添加特殊的十六进制代码。但是,文章说,如果我们实现 Serializable 接口,则会将 AC ED 代码添加到类文件中。
  • 不,您误读了这篇文章。 AC ED 是序列化数据中的魔法标记!它没有写入.class 文件。
  • 感谢这个很好的解释。 :)
【解决方案3】:
package com.example;
interface MarkerInterface {}

给你一个。直接复制粘贴到com/example/MarkerInterface.java,编译使用!

这是一个用法示例:

class SomeClass implements MarkerInterface {
    // ...
}

【讨论】:

    【解决方案4】:

    您不能像java.io.Serializable 接口那样创建对JVM 有意义的标记接口。但是,您可以创建一个标记接口,使用instanceof 在您自己的代码中进行检查。

    但是,由于我们有annotations,因此通常不鼓励以这种方式使用标记接口。以各种方式标记类方法和字段,以便在编译时使用Annotation Processing Tool (apt) 或在运行时使用反射进行后续处理,这就是创建注释的目的。

    所以与其创建一个标记界面并像这样使用它:

    class MyClass implements MyMarkerInterface {
    }
    

    您可能应该创建一个注释并像这样使用它:

    @MyAnnotation
    class MyClass {
    }
    

    【讨论】:

      【解决方案5】:

      取决于您对标记界面的理解。但一般情况下,您可以在代码中使用instanceof 来检查一个实例是否实现了 Marker 接口,然后对这个实例做一些事情......

      【讨论】:

      • 我了解对于标记接口,编译器(javac.exe)在.class文件中添加了特殊代码。因此,因此,不可能编写 Marker 接口。请澄清。 :)
      • 正如 Joachim Sauer 在他的回答中所说,标记接口是普通的 Java 接口,它们是空的(不包含方法声明)。 Serializable 标记接口很特别,对,因为编译器添加了默认的序列化实现。但是没有什么能阻止您编写自己的在运行时有用的标记接口(例如 instanceof)。无论如何,我认为既然Java现在提供了对注解的支持,那么应该使用它们来代替标记接口。
      猜你喜欢
      • 2018-04-18
      • 1970-01-01
      • 2018-12-01
      • 2021-02-03
      • 2010-12-24
      • 2011-01-10
      • 2013-11-02
      • 2019-08-31
      相关资源
      最近更新 更多