整合自定义注解

一、@Target的用法


java.lang.annotation.Target

用于设定注解使用范围

java.lang.annotation.ElementType

Target通过ElementType来指定注解可使用范围的枚举集合


二、ElementType的用法

 

取值注解使用范围
METHOD可用于方法上
TYPE可用于类或者接口上
ANNOTATION_TYPE可用于注解类型上(被@interface修饰的类型)
CONSTRUCTOR可用于构造方法上
FIELD可用于域上
LOCAL_VARIABLE可用于局部变量上
PACKAGE用于记录java文件的package信息
PARAMETER可用于参数上

这里重点说明下:ElementType. PACKAGE。它并不是使用在一般的类中,而是用在固定的文件package-info.java中。这里需要强调命名一定是“package-info”。由于package-info.java并不是一个合法的类,使用eclipse创建类的方式会提示不合法,所以需要以创建文件的方式来创建package-info.java。

例如,定义可使用范围PACKAGE:

 

那么,创建文件:package-info.java,内容如下:

复制代码 代码如下:


@AsynLog
package org.my.commons.logs.annotation;

重点说明:注解只能在ElementType设定的范围内使用,否则将会编译报错。例如:范围只包含ElementType.METHOD ,则表明该注解只能使用在类的方法上,超出使用范围将编译异常。

 

 

@Retention注解

日常开发中经常用到注解,所以也会经常使用到@Retention注解,写下这篇文章做个记。
Reteniton的作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中

public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}
  • SOURCE
    被编译器忽略

  • CLASS
    注解将会被保留在Class文件中,但在运行时并不会被VM保留。这是默认行为,所有没有用Retention注解的注解,都会采用这种策略。

  • RUNTIME
    保留至运行时。所以我们可以通过反射去获取注解信息。

下面,我们通过一个例子去验证一下。我定义了不同策略的注解去注解了三个方法

@Retention(RetentionPolicy.SOURCE)
public @interface SourceLevel {
}
@Retention(RetentionPolicy.CLASS)
public @interface ClassLevel {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeLevel {
}

public class Test {

    @SourceLevel
    public void sourceLevel(){}
    @ClassLevel
    public void classLevel(){};
    @RuntimeLevel
    public void runtimeLevel(){};

}

通过javap获取到Test类的字节码

public void sourceLevel();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 5: 0

  public void classLevel();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 7: 0
    RuntimeInvisibleAnnotations:
      0: #11()

  public void runtimeLevel();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 9: 0
    RuntimeVisibleAnnotations:
      0: #14()

 

我们可以看到

1. 编译器并没有记录下sourceLevel方法的注解信息
2. 编译器分别使用了RuntimeInvisibleAnnotations和RuntimeVisibleAnnotations属性去记录了classLevel和runtimeLevel的注解信息

以上。

 

 

 

注解的使用非常简单,只需在需要注解的地方标明某个注解即可,例如在方法上注解:

 

public class Test {

    @Override

    public String tostring() {

        return "override it";

    }

}

例如在类上注解:

@Deprecated

public class Test {

}

所以Java内置的注解直接使用即可,但很多时候我们需要自己定义一些注解,例如常见的spring就用了大量的注解来管理对象之间的依赖关系。下面看看如何定义一个自己的注解,下面实现这样一个注解:通过@Test向某类注入一个字符串,通过@TestMethod向某个方法注入一个字符串。

1.创建Test注解,声明作用于类并保留到运行时,默认值为default。

@Target({ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)

public @interface Test {

String value() default "default";

}

2.创建TestMethod注解,声明作用于方法并保留到运行时。

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface TestMethod {

String value();

}

3.测试类,运行后输出default和tomcat-method两个字符串,因为@Test没有传入值,所以输出了默认值,而@TestMethod则输出了注入的字符串。

 

@Test()

public class AnnotationTest {

@TestMethod("tomcat-method")

public void test(){

}

public static void main(String[] args){

Test t = AnnotationTest.class.getAnnotation(Test.class);

System.out.println(t.value());

TestMethod tm = null;

try {

tm = AnnotationTest.class.getDeclaredMethod("test",null).getAnnotation(TestMethod.class);

} catch (Exception e) {

e.printStackTrace();

}

System.out.println(tm.value());

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值