JVM如何处理标记接口
标记界面没有任何东西。 它只包含接口声明,然后由JVM如何处理实现此标记接口的类?
我们可以创建任何新的标记接口吗?
您的问题应该是编译器如何处理标记接口,答案是: 与其他任何接口没有区别 。 例如,假设我声明了一个新的标记接口Foo
:
public interface Foo { }
…然后声明一个实现Foo
的类Bar
:
public class Bar implements Foo { private final int i; public Bar(int i) { this.i = i; } }
我现在能够通过类型Foo
的引用引用Bar
的实例:
Foo foo = new Bar(5);
…并且还检查(在运行时)对象是否实现了Foo
:
if (o instanceof Foo) { System.err.println("It's a Foo!"); }
后一种情况通常是使用标记接口的驱动因素; 前一种情况几乎没有什么好处,因为没有可以在Foo
上调用的方法(没有先尝试向下转换)。
就编译器和JVM而言,标记接口和任何其他接口之间完全没有区别。
是的,您可以随意创建标记界面。
然后JVM如何处理实现此标记接口的类?
实现Java标记接口的类实例受益于特定行为,因为某些JDK类或HotSpot JVM为它们提供了特定的行为。
例如,使用Serializable
接口。
如果深入了解ObjectOutputStream
和ObjectInputStream
您可以看到序列化/反序列化行为是在其中实现的。
下面是ObjectOutputStream.writeObject0()
调用的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()); } } ... } }
对于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
的非常好的答案显示了这样做的一般想法。
标记接口有助于识别被检查对象是否实际上是我们感兴趣的类型(已实现的接口)。但是它与其他接口没有区别(除了它们没有任何行为义务)
例如, ObjectOutputStream
可以发现,如果一个类实现了Serializable
,那么用户已明确表明他同意该对象可以被序列化。
我觉得幕后可能有一些逻辑。 在尝试调用clone()而不实现Cloneable时,我们如何得到CloneNotSupportedException,除非编译器在查看clone()时有一些指导来检查一些事情!
http://javamagic.wordpress.com/2011/12/02/marker-interface-in-java-what-why-uses-etc/
根据这个线程( 标记界面中的混乱 ),这些都是标记接口………. Serializable,Clonable,SingleThreadModel,EventListener,RandomAccess,Remote等。
如果场景背后没有逻辑或没有JVM /编译器对它们进行不同处理的特殊指令,那么它们如何表现为它们的预期(&JVM /编译器理解Clonable和Serializable之间的区别)?
在这种情况下,“可序列化”这个词令人困惑,因为像我这样的许多新手程序员都认为“序列化”接口可以进行序列化,即将抽象数据类型转换为字节的过程。 但正如文献所示,可序列化接口只是一个“标记”,将ADT转换为字节的实际工作(我将其称为获取元数据的过程)由ObjectOutputStream完成。 类似地,反序列化由ObjectInputStream完成。
以clone()
为例。 实际上, clone()
是在Object
类中定义的。 但它protected
。 只有当您的类正在实现Cloneable
接口时,才能使用它。 因此,当您实现Cloneable
,您将获得使用clone()
的权利。 接口不包含任何方法! 得到它了 ?