Java 中的 tagging interface

什么是 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。

你可能感兴趣的:(Java)