aaa*_*aaa 10 java interface marker-interfaces java-8 default-method
我认为它不能,因为标记接口原则是没有任何方法,但由于默认方法不是抽象的我不确定.
Aza*_*zar 12
就Java而言,"标记"接口只是一个常规接口.因此,它可以像任何(Java-8)接口一样具有默认方法.
现在,至于这是否违反了Marker界面的原则,我不得不说是.Marker接口应该充当各种标志,仅标识一个类符合某些外部标准.现在,它可以是Marker接口并具有抽象/默认方法,但它将不再纯粹满足定义.
来自Effective Java(第二版):
标记接口是一个不包含方法声明的接口,但只是指定(或"标记")一个实现接口具有某些属性的类.
标记接口是一种设计模式,因此我们可以通过观察定义是什么来开始回答您的问题:
在早期版本的Java中,标记接口是声明类的元数据的唯一方法.例如,Serializable Marker Interface允许类的作者说序列化和反序列化时它们的类将正常运行.
在Java的上下文中,Marker接口的目的是说出关于该类的信息.有趣的是,它标志着它.这方面的一个例子就是Serializable接口,除了标记a Class能够序列化为a之外什么也没做String.这里的问题是:
定义是否包含功能?
不,我不这么认为.功能不仅仅是关于类的元数据; 它有助于定义类本身.从元数据到数据需要一步.因此,就设计模式而言,标记接口无法定义或声明功能; 它可以简单地说明实施Class.
虽然@Azar的答案是正确的,但我们不能忘记在引入默认方法之前编写了Effective Java .
有两种查看标记接口的方法:
"官方"定义是第一个,但直到Java 7,这两个陈述是相同的.它是Effective Java中的一种重复模式,一旦发布了接口,就无法向其添加任何方法,因为它会强制实现新方法.
但是,这正是默认方法试图解决的问题:允许接口的演进,而无需改进实现它们的所有类.它还使上面的两个语句意味着略有不同:默认方法明显违反语句1,并且设计不违反语句2.
想象一下,您编写了一个XML序列化引擎,并创建了一个标记接口XmlSerializable来配合它:
public interface XmlSerializable {}
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但是后来你意识到你实际上有一些需要特殊处理的课程,他们需要提供自己的定制转换器.所以你可能做的是这样的:
public interface XmlSerializable {
public static final Map<Class,Class> CONVERTERS = ...
default Class customConverter() {
return CONVERTERS.get(this.getClass());
}
}
Run Code Online (Sandbox Code Playgroud)
那会XmlSerializable不会成为标记界面?你可以说它仍然是一个标记界面,因为你没有真正直接向界面添加额外的行为,只有影响序列化引擎行为的额外元数据.另一方面,这个解决方案允许实现类重写customConverter(),这有点狡猾,标记接口不应该允许.(话说回来,就是Serializable和Cloneable依托实现类"神奇"的方法更好吗?我不这么认为.)
可以说上面的例子并不是解决这类问题的好方法,使用注释可能会好得多.但对大多数"真正的"标记界面也是如此.
我们可以得出结论,只有默认方法的接口或多或少等同于空接口.如果你想进行理论上的区分而不是称之为标记界面,那当然没问题.但是实际上没什么区别,并且考虑到标记界面的固有问题,我们应该尽量避免它们.
标记接口可以具有默认方法,但具有它们是荒谬的.
标记界面与传统界面的使用方式不同.传统的接口定义了抽象和默认的方法.因此,程序使用该接口声明变量作为其类型,并通过该接口类型的引用来调用这两种类的方法是明智的.
通过约束,标记接口不用于调用方法.它是关于通过类型系统声明的对象的元信息.它通常通过instanceof表达式调用代码,或偶尔使用Class.isAssignableFrom().声明一个类型是标记接口的变量是没有意义的,因为对这样的变量没什么可做的.
在JDK标志接口的例子是Cloneable,RandomAccess,和Serializable.
现在考虑在某些标记界面中添加默认方法:
interface Marker {
default void foo() { ... }
}
Run Code Online (Sandbox Code Playgroud)
什么可以默认执行foo?
默认方法的实现通常希望操作this,并且它们通过调用其他实例方法来实现this.他们可以调用其他默认方法,但是让一堆默认方法相互调用是没有用的.最终,this必须进行某种实际操作.由于接口方法无法访问状态(字段),因此任何实际操作都必须由驻留在实现类中的抽象方法实现来执行.但是,在标记界面中没有这样的方法.
默认实现foo可以在此接口或其他类上调用静态方法.这大多没有意义,因为这样的方法首先可能更好地表达为静态方法.实现可以传递this给静态方法,但是这个方法对这样的引用没有任何用处,因为它没有方法!好吧,它可能有默认方法,但现在我们进入圈子.
对于在接口上有用的默认方法,该接口也需要具有抽象方法.但如果它有抽象方法,它就不再是标记接口.因此,在标记接口上使用默认方法是没有意义的.
| 归档时间: |
|
| 查看次数: |
1168 次 |
| 最近记录: |