我被告知Java中的Marker接口是一个空接口,用于向编译器或JVM发出信号,表明必须以特殊方式处理实现此接口的类的对象,如序列化,克隆等.
但最近我了解到它实际上与编译器或JVM无关.例如,在的情况下,Serializable接口的方法writeObject(Object)的ObjectOutputStream不喜欢的东西instanceOf Serializable,以检测类实现是否Serializable与抛出NotSerializableException相应.一切都在代码中处理,这似乎是一个设计模式,所以我认为我们可以定义自己的标记接口.
现在我怀疑了:
上面提到的标记接口的定义在第一点是错误的吗?那么我们如何定义Marker接口呢?
而不是使用instanceOf运算符为什么不能使方法类似于writeObject(Serializable)有一个编译时类型检查而不是运行时?
注释如何比标记接口更好?
它已经讨论过堆栈溢出,我们应该更喜欢属性标记接口(接口没有任何成员).MSDN上的接口设计文章也断言了这个建议:
避免使用标记接口(没有成员的接口).
自定义属性提供了标记类型的方法.有关自定义属性的更多信息,请参阅编写自定义属性.如果可以在执行代码之前推迟检查属性,则首选自定义属性.如果您的方案需要编译时检查,则无法遵守此准则.
甚至还有一个FxCop规则来强制执行此建议:
避免空接口
接口定义提供行为或使用合同的成员.无论类型在继承层次结构中出现何种位置,接口描述的功能都可以采用任何类型.类型通过为接口的成员提供实现来实现接口.空接口不定义任何成员,因此,不定义可以实现的合同.
如果您的设计包含期望实现类型的空接口,则可能使用接口作为标记,或者标识一组类型的方法.如果此标识将在运行时发生,则完成此操作的正确方法是使用自定义属性.使用属性的存在或不存在或属性的属性来标识目标类型.如果标识必须在编译时进行,则可以使用空接口.
本文仅说明了您可能忽略警告的一个原因:何时需要对类型进行编译时识别.(这与界面设计文章一致).
如果在编译时使用接口标识一组类型,则可以安全地从此规则中排除警告.
实际问题是:Microsoft在框架类库的设计中(至少在几种情况下)不符合他们自己的建议:IRequiresSessionState接口和IReadOnlySessionState接口.ASP.NET框架使用这些接口来检查它是否应该为特定处理程序启用会话状态.显然,它不用于类型的编译时识别.他们为什么不这样做?我可以想到两个潜在的原因:
微优化:检查对象是否实现接口(obj is IReadOnlySessionState)比使用反射检查属性(type.IsDefined(typeof(SessionStateAttribute), true))更快.大多数时候差异可以忽略不计,但它实际上可能对ASP.NET运行时中的性能关键代码路径很重要.但是,他们可以使用的解决方法就像为每个处理程序类型缓存结果一样.有趣的是,ASMX Web服务(具有类似性能特征)实际上使用EnableSession属性的WebMethod属性来实现此目的.
与使用第三方.NET语言的属性装饰类型相比,可能更有可能支持实现接口.由于ASP.NET被设计为与语言无关,并且ASP.NET 根据指令的属性为类型(可能在CodeDom的帮助下以第三方语言生成)生成代码,因此可能会生成更多感觉使用接口而不是属性.EnableSessionState<%@ Page %>
使用标记接口而不是属性的有说服力的原因是什么?
这只是一个(过早?)优化还是框架设计中的一个小错误?(他们认为反射是"红眼睛的大怪物"吗?)思想?
什么都没有在Serializable等标记接口中实现..实施它有什么用?
如果Serializable接口只是一个标记接口,用于传递有关java中类的元数据 - 我有点困惑:
在阅读了java的序列化算法(元数据从下到上,然后是从上到下的实际实例数据)的过程之后,我无法真正理解通过该算法无法处理哪些数据.
简而言之:
NotSerializableException?implements Serializable为我的课程添加条款?为什么不ObjectOutputStream.writeObject(Object o)带Serializable?为什么要服用Object?
我想问为什么java注释使用了这么多...我知道他们替换了例如jpa中的xml配置,但为什么这种配置会被使用呢?考虑一下这段代码:
@Entity
class Ent{
// some fields
}
//... somewhere in the other file far far away
class NonEnt{
// whatever here
}
Run Code Online (Sandbox Code Playgroud)现在,当我尝试将其置于持久化上下文中时,使用EntityManager's persist方法,我会在尝试持久化NonEnt实例时遇到运行时错误(更好的是获得编译错误).对我来说有明显的解决方案,强制实体实现一些无方法接口,而不是使用@Annotations.但这在框架设计师中并不流行,这个解决方案的缺点是什么?在Java中,我们使用序列化的writeObject(Object obj)方法.ObjectOutputStreamObject
但是因为该方法只接受实现java.io.Serializable接口的对象(或者它会抛出NotSerializableException),为什么它仍然使用Object参数而不是Serializable像writeObject(Serializable o)?
有任何设计考虑因素吗?
我认为它不能,因为标记接口原则是没有任何方法,但由于默认方法不是抽象的我不确定.
我在使用标记接口或空抽象类之间做出决定时遇到困难.
我有两个类BrokerResponse和Notification,不具有结构相似性.连接它们的唯一方法是需要订阅.
void register(Receivable receivable, BrokerObserver observer)
Run Code Online (Sandbox Code Playgroud)
我不知何故不喜欢使用a Marker Interface,因为它违反了a 的基本定义Interface.另一方面,使用abstract super课程会让我感到不舒服,因为这两个课程彼此没有关系.
在这种情况下,通常更可取的方法是什么?为什么?
我忘了提一下,这BrokerResponse是一个抽象类本身,它有几个子类来确定相应的类型.
任何人都可以详细说明Java中Null接口和Marker接口之间的核心区别是什么.我在一次采访中被问到这个问题.
谢谢.