自定义注解

一:自定义注解的基本格式

public @interface 注解名称 {}
比如:public @interface Anno1 {}
底层帮我们自动实现java.lang.annotation.Annotation接口

二:注解的属性

1、注解属性的定义和接口中方法的定义类似,默认是public,所以public可以省略。

public 类型 属性名称()  [default  …]; 可以default指定默认值
public String name();

2、属性定义可以通过default为属性指定默认值,指定默认值的属性,在注解使用时,可以为之赋值,也可以不为之赋值。如果不通过default为属性指定默认值,在注解使用必须使用该属性并且还得为之赋值。

public @interface TestAnnotation{
    public int id() default 1;
    public String name() default "tom";
    public String sex();
}
//sex属性必须使用并赋值
@TestAnnotation(id=3,sex="man")
public class Test {

}

3、注解中有一个特殊的属性value,如果仅为该属性赋值,”value=”可以省略掉,但是如果和其他属性同时赋值,“value=”则不能省略。和该属性的类型无关,仅和名称有关(只要名称叫value,就可以省略”value=”)

public @interface TestAnnotation{
    public String value();
}
//sex属性必须使用并赋值
@TestAnnotation("ceshi")
public class Test {

}

4、属性的类型可以八种基本数据类型、类、枚举、注解、String等,以及以上类型的一维数组。

自定义注解:
public @interface MetaAnnotation {
    String value();//元注解MetaAnnotation设置有一个唯一的属性value
}
public enum EumTrafficLamp {
    RED,//红
    YELLOW,//黄
    GREEN//绿
}
public @interface TestAnnotation{
    public String value();
    int[] arr() default {1,2,4};
    EumTrafficLamp lamp() default EumTrafficLamp.RED;
    MetaAnnotation annotationAttr() default @MetaAnnotation("cc");
}

应用注解:
@TestAnnotation(
    value="ceshi",
    arr={2,4,5},
    lamp=EumTrafficLamp.GREEN,
    annotationAttr=@MetaAnnotation("ca")
)
//如果数组属性只有一个值,这时候属性值部分可以省略大括号,如:@TestAnnotation(arrayAttr=2),这就表示数组属性只有一个值,值为2

三:源生注解:用于修饰注解的注解(只能修饰注解)

@Target(ElementType.XXX):表示被修饰的注解能够在什么元素(类和接口,方法、属性、成员变量、构造方法..)上使用

ANNOTATION_TYPE 注解类型声明
CONSTRUCTOR构造方法声明
FIELD 字段声明(包括枚举常量)
LOCAL_VARIABLE 局部变量声明
METHOD方法声明
PACKAGE包声明
PARAMETER参数声明
TYPE类、接口(包括注解类型)或枚举声明
    //表示该注解只能被用在方法上
    @Target(ElementType.METHOD)
    public @interface TestAnnotation{
    }

在定义注解时,如果没有使用Target指定,默认都可以使用。如果使用了Target指定使用的位置,那么该注解只能在所指定的位置使用。

@Retention(RetentionPolicy.SOURCE):表示注解的保留域。

RetentionPolicy.SOURCE:给编译器看,编译器编译后该类型的注解就被丢弃掉了。(生成的.class字节码文件中,将不再存在该类型的注解)
RetentionPolicy.CLASS:字节码级别的,给类加载器看的,在类被加载时做一些引导相关的一些操作。编译器编译保留(在.class字节码文件中保留),类加载器加载时使用,加载后丢弃掉。
RetentionPolicy.RUNTIME:给JVM看的,编译器编译后保留,类加载器加载保留,在运行时,JVM使用。
通常自定义的注解都是使用该保留域,在程序运行时反射注解中的信息,并根据属性的值做相关的操作。

@Documented:表示生成的javadoc中是否保留注解的信息。

@Inherited:父类所使用的注解如果被@Inherited修饰,子类可以继承父类对应的注解

四:jdk内部自带注解

@Deprecated 表示被修饰的元素(类、构造方法、方法、属性…)已经过时,不建议使用
@Override 表示重写父类的方法
@SuppressWarnings 抑制编译器显示警告信息

五:反射注解

@Retention(RetentionPolicy.RUNTIME)
如果注解想要被反射,注解的保留域必须设置为RUNTIME保留域,否则反射不到。

1. 定义一个注解类

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface MyAnnotation {
    int value();
}

2. 定义一个类使用注解类

public class MyBean {

    @MyAnnotation(20)
    private int value;

    @Override
    public String toString() {
        return String.valueOf(value);
    }
}

3. 反射注解

public static void main(String[] args) {
        try {
            Field field = MyBean.class.getDeclaredField("value");//获取成员变量value
            field.setAccessible(true);//将value设置成可访问的
            if(field.isAnnotationPresent(MyAnnotation.class)){//判断成员变量是否有注解

                MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);//获取定义在成员变量中的注解MyAnnotation
                int value = myAnnotation.value();//获取定义在MyBean的MyAnnotation里面属性值
                System.out.println(value);//20

                Class<MyBean> clz = MyBean.class;
                MyBean myBean = clz.newInstance();  //创建MyBean实例对象

                field.setInt(myBean, value);//将注解的值20可以赋给成员变量
                System.out.println(myBean);//验证结果
            }
        } catch (Exception e) {
            e.printStackTrace();
        };
    }
  • 2
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值