学习Java时,很早就接触过注解的概念,子类复写父类方法时要在方法前添加一行“@Override”,不过这个注解只是起到一个提示的效果,在逻辑上并没有什么实际作用。
在一些第三方框架中,我们经常能看到一些自定义的注解,这些注解可以使配置操作变得非常简单。
举个例子,最近接触到的EventBus框架,在实现订阅事件的方法时,需要对这个方法进行一些配置(比规定事件所在的线程)。这时候,不需要你去调用setXXX()这样的方法,仅仅需要在定义这个方法前加上一行“@Subscribe(treadMode=xxxx)”,就能完成配置,非常简洁。
下面来介绍一下如何使用自定义注解。
使用“@iterface”定义一个注解,这里和定义一个class/interface很像:
public @interface MyAnnotation{ String s() ; int i() default 0; }
然后我在这个自定义的注解里添加了两个成员变量s和i,定义成员变量的形式和定义方法一样,方法的参数为空,返回值类型即是成员变量的类型,default后面是成员变量的默认值。
要注意的是,注解里是没有成员方法的。
另外,可以用四种“元注解”对你的自定义注解进行一些设置和约束(可以理解为注解的注解):
@Target:规定注解作用的目标,其成员变量只有一个,是ElementType里定义的值,可以设置为:
CONSTRUCTOR 该注解仅应用于构造函数 FIELD 该注解仅应用于字段 LOCAL_VARIABLE 该注解仅应用于局部变量 METHOD 仅应用于方法 PACAKGE 仅应用于包 PARAMETER 仅应用于参数 TYPE 仅应用于类型
示例:
@Target(ElementType.METHOD) public @interface MyAnnotation{ }
这样就表明了MyAnnotation注解只应用于方法。如果不设置@Target,就默认该注解可以应用于任何地方。
其余元注解(@Repeatable、@Inherited、@Document)这里就不再逐一介绍。
现在我们创建好了一个自定义的注解MyAnnotation,就可以将它应用在我们之前通过@Target规定的地方。
例如,在某个方法前添加一行注解:
@MyAnnotation(s = "XXX",i = 1) public void test(){ //... }
这里对注解的s和i两个属性进行了赋值,赋值的形式就是name = value,如果不赋值,就会指定为default设定的值。
最开始已经说过,自定义的注解可以使配置操作变得非常简单。现在我们已经通过MyAnnotion注解,给test这个方法设定了两个配置参数,那么如何取得这两个参数的值呢?
这就要用到java的反射机制了。
Method method = 方法所在的类名.class.getMethod("test",null); //通过反射获取test方法实例 if (method.isAnnotationPresent(MyAnnotation.class)){ //判断是否设置注解 MyAnnotation myAnno = method.getAnnotation(MyAnnotation.class); System.out.println(myAnno.s() + myAnno.i()); }
运行这段代码,可以看到输出了之前在注解里设置的“XXX"和"1"。