JVM如何处理标记接口

sri*_*ini 6 java jvm

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

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

Ada*_*ski 15

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

public interface Foo {
}
Run Code Online (Sandbox Code Playgroud)

...然后声明一个Bar实现的类Foo:

public class Bar implements Foo {
  private final int i;

  public Bar(int i) { this.i = i; }
}
Run Code Online (Sandbox Code Playgroud)

我现在能够Bar通过类型的引用引用一个实例Foo:

Foo foo = new Bar(5);
Run Code Online (Sandbox Code Playgroud)

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

if (o instanceof Foo) {
  System.err.println("It's a Foo!");
}
Run Code Online (Sandbox Code Playgroud)

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

  • 给出的答案非常完美和清晰.我正在经历"ObjectOutputStream"类,而writeObject0方法正在检查Object是否是Serializable实例类型(obj instanceof Serializable).如果不是,则抛出NotSerializableException.除了像String,ArrayList等大多数常规类已经实现了Serializable接口之外,所以有时它会从我们的脑子里跳出来检查我们想序列化的类是否正在实现接口. (4认同)
  • 必须有一种JVM理解这个接口是标记接口的方式,如果JVM遇到标记接口,它应该采取一些行动.如果我声明一个没有方法的接口,并希望任何实现它的类都可以序列化,它将无法工作:-) (3认同)
  • @Pankaj No. JVM并不关心.执行检查的是*Java代码*. (2认同)

dav*_*xxx 5

那么JVM对于实现这个标记接口的类是如何处理的呢?

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

以接口为例Serializable
如果您深入研究ObjectOutputStreamObjectInputStream您会发现序列化/反序列化行为是在 中实现的。

ObjectOutputStream.writeObject0()这是调用 by的片段,ObjectOutputStream.writeObject()说明了这一点:

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());
                }
            }
            ...
    }
}
Run Code Online (Sandbox Code Playgroud)

对于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 
Run Code Online (Sandbox Code Playgroud)

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

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

如果您创建自己的标记接口,则应该像 JVM 和 JDK 类那样处理实现 Java 标记接口的类的内置实例:即添加代码来专门处理标记接口的实例。
非常好的答案Adamski显示了这样做的总体思路。