Java 中的 tagging interface
- 2020 年 3 月 27 日
- 筆記
什么是 tagging interface?
在 Servlet 源码中,所有的监听器类都实现了空接口 EventListener,代码如下所示:
package java.util; /** * A tagging interface that all event listener interfaces must extend. * @since JDK1.1 */ public interface EventListener { }
说到这是一个 tagging interface,也就是标签接口,所有的时间监听器接口都需要继承这个接口。其次,显而易见的是,这个接口没有任何方法或者抽象方法。
那么 tagging interface 是什么意思呢?
在 Java 中实现或继承接口通常是为了给当前类或接口某种功能。既然 tagging interface 没有抽象方法,那么此接口就不是用于赋予实现此接口的类某种功能。
所以说,如果以 tagging interface 进行面向接口编程并不是一个好选择。具体来说,如下代码所示:
class MyListener implements EventListener{ //声明一些类方法 publiv void foo(){ } } class Test{ public void test (EventListener el){ (MyListener)el.foo(); } }
因为 EventListener
接口是一个空接口,所以即使面向此接口编程,只会落到在此申明下无法调用任何方法的境地,所以必须要强制类型转换。而一旦强制类型转换,那么面向接口编程实际上也失去了意义。
所以虽然 tagging interface 可以告诉程序员:这是一个属于某种类型的类或接口,但是程序员并不能从中收益。标签的意义在于告诉 VM 这是一个事件监听类,你可以为此采用一些特殊的优化技巧(比如 Serializable 也是个标签类,它用于告诉 JVM 可以进行为实现此接口的类序列化以及采用一些优化手段)。
或者可以进行类型检查,符合要求才进行下一步操作,比如:
if(el instanceof EventListner){ el.foo(); }
tagging interface 的历史悠久,实际上在 JDK 1.5 提供的注解开始,其一部分功能被取代了。
比如:
@Serializable() public class MyClass { }
注解 @Serializable()
给 MyClass 类打上了相应标签,为了检查当前类是否打上对应标签,可以使用 Class 对象的 isAnnotationPresent
方法,而不是 instanceof
关键字,如下所示:
MyClass mc =new MyClass(); if(mc.getClass().isAnnotationPresent(Serializable.class)){ //调用方法 }
可见,注解和 tagging interface 类可以起到相同的作用:给类/接口打上标签。
另一方面,注解和 tagging interface 有着一定的区别。
tagging interface 比注解有着更强的限制能力。这是因为注解如果能作用于类,那么此注解必然使用了元注解 @ElementType.TYPE
,也就表明这个注解能够打在任何其他类上。而 tagging interface 通过继承的技巧能够限定相关类必须实现某个其他接口。
interface Marker extends Foo { }
如上的 Marker 是一个 tagging interface,但是其额外继承于 Foo 接口,所以实现了 Marker 接口的类虽然不需要实现来自 Marker 接口的任何方法,但是要实现来自 Foo 的方法。这便是带有 Foo 接口限制的标签接口 Marker。