JVM如何处理标记接口

时间:2011-10-17 09:29:19

标签: java jvm

Marker界面没有任何东西。它只包含接口声明,然后由JVM如何处理实现此标记接口的类?

我们可以创建任何新的标记接口吗?

7 个答案:

答案 0 :(得分:15)

您的问题应该是编译器如何处理标记接口,答案是:与其他任何接口没有区别。例如,假设我声明了一个新的标记接口Foo

public interface Foo {
}

...然后声明实现Bar

的类Foo
public class Bar implements Foo {
  private final int i;

  public Bar(int i) { this.i = i; }
}

我现在可以通过Bar类型的引用引用Foo的实例:

Foo foo = new Bar(5);

...并且还检查(在运行时)对象是否实现Foo

if (o instanceof Foo) {
  System.err.println("It's a Foo!");
}

后一种情况通常是使用标记接口的驱动因素;前一种情况几乎没有什么好处,因为没有可以在Foo上调用的方法(没有先尝试向下转发)。

答案 1 :(得分:4)

就编译器和JVM而言,标记接口和任何其他接口之间完全没有区别。

是的,您可以随意创建标记界面。

答案 2 :(得分:3)

  

然后由JVM对实现的类如何处理   这个标记界面?

实现Java标记接口的类的实例受益于特定的行为,因为某些JDK类或HotSpot JVM为它们提供了特定的行为。

例如,使用Serializable界面。
如果深入研究ObjectOutputStreamObjectInputStream,您会发现实现了序列化/反序列化行为。

以下是ObjectOutputStream.writeObject()调用的ObjectOutputStream.writeObject0()的摘要,说明了这一点:

public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants {

   ...
   private void writeObject0(Object obj, boolean unshared) throws IOException   {
            ...    
            if (obj instanceof String) {
                writeString((String) obj, unshared);
            } else if (cl.isArray()) {
                writeArray(obj, desc, unshared);
            } else if (obj instanceof Enum) {
                writeEnum((Enum<?>) obj, desc, unshared);
            } else if (obj instanceof Serializable) {
                writeOrdinaryObject(obj, desc, unshared);
            } else {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
            ...
    }
}

对于Cloneable接口,请查看Object.clone()方法,您将看到它引用了应用Cloneable规范的本机方法。

在HotSpot源代码src\share\vm\prims\jvm.cpp中,您可以找到Object.clone()实现:

JVM_ENTRY(jobject, JVM_Clone(JNIEnv* env, jobject handle))
  JVMWrapper("JVM_Clone");
  Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
  const KlassHandle klass (THREAD, obj->klass());
  JvmtiVMObjectAllocEventCollector oam;

  // I skip all the processing that you can read in the actual source file
  ...

  return JNIHandles::make_local(env, oop(new_obj));
JVM_END 

对于此标记器接口,其行为不是直接在JDK类中实现,而是由JVM本身实现,但总体思路是相同的。

  

我们可以创建任何新的标记器接口吗?

如果创建自己的标记接口,则应像JVM和JDK类那样处理实现Java标记接口的类的内置实例:即添加代码以专门处理标记接口的实例。
Adamski的很好回答说明了这样做的总体思路。

答案 3 :(得分:0)

标记界面有助于识别被检查对象是否实际上是我们感兴趣的类型(已实现的界面)。但是它与其他界面没有区别(除了它们没有任何行为义务)

例如,ObjectOutputStream可以发现,如果一个类实现Serializable,那么用户已明确表示同意该对象可以被序列化。

答案 4 :(得分:0)

我觉得幕后可能有一些逻辑。在尝试调用clone()而不实现Cloneable时,我们如何得到CloneNotSupportedException,除非编译器在查看clone()时有一些指导来检查一些事情!

http://javamagic.wordpress.com/2011/12/02/marker-interface-in-java-what-why-uses-etc/

根据这个帖子(Confusion in marker interface),这些都是标记接口.......... Serializable,Clonable,SingleThreadModel,EventListener,RandomAccess,Remote等。

如果场景背后没有逻辑或没有JVM /编译器对它们进行不同处理的特殊指令,那么它们如何表现为它们的预期(&amp; JVM /编译器理解Clonable和Serializable之间的区别) )?

答案 5 :(得分:0)

“serializable”这个词在这种情况下令人困惑,因为像我这样的许多新手程序员都认为“可序列化”接口可以进行序列化,即将抽象数据类型转换为字节的过程。但正如文献所示,可序列化接口只是一个“标记”,将ADT转换为字节的实际工作(我将其称为获取元数据的过程)由ObjectOutputStream完成。类似地,反序列化由ObjectInputStream完成。

答案 6 :(得分:-1)

clone()为例。实际上clone()是在Object类中定义的。但它是protected。只有当您的类正在实现Cloneable接口时,才能使用它。因此,当您实施Cloneable时,您将获得使用clone()的权利。界面不包含任何方法!得到它了 ?