Java 注解 讲解

注解可以被标注在任意地方,包括方法上、类名上、参数上、成员属性上、注解定义上等,就像注释一样,它相当于我们对某样东西的一个标记。而与注释不同的是,注解可以通过反射在运行时获取,注解也可以选择是否保留到运行时

预设注解

JDK预设了以下注解,作用于代码:

  • @Override - 检查(仅仅是检查,不保留到运行时)该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告(仅仅编译器阶段,不保留到运行时)
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。

元注解

元注解是一种最基本的注解,应用到其他的注解上面

元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5种

@Retention

Retention 的英文意为保留期的意思,当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的存活时间。

它的取值如下:

  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
@Documented

能够将注解中的元素包含到 Javadoc 中去

Target 是目标的意思,@Target 指定了注解运用的地方。

你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。

@Target 有下面的取值

  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

说的比较抽象,代码来解释。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}

注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。

可以这样理解:

老子非常有钱,所以人们给他贴了一张标签叫做富豪。

老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。

老子的孙子长大了,自然也是富豪。

这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。

@Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。

// 定义一个容器注解, 其value属性的数据类型是 Role 注解类型的数组
public @interface Person{
	Role[] value();
}

// 定义 Role 注解, 使用@Repeatable注解标识 Role 注解与Person注解之间的关系
@Repeatable(Persons.class)
public @interface Role{
	String role() default " ";
}

@Role(role="artist")
@Role(role="coder")
@Role(role="PM")
public class SuperMan{
}

// 两种方式等价,作用相同
@Person({@Role("artist"),@Role("coder"),@Role("PM")})
public class SuperMan{
}
@interface Persons {
    Role[]  value();
}
@Repeatable(Persons.class)
@interface Person{
    String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}

注解的使用

我们还可以在注解中定义一些属性,注解的属性也叫做成员变量,注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    String value();
}

默认只有一个属性时,我们可以将其名字设定为value,否则,我们需要在使用时手动指定注解的属性名称,使用value则无需填入:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    String test();
}
public class Main {
    @Test(test = "")
    public static void main(String[] args) {
    }
}

我们也可以使用default关键字来为这些属性指定默认值

当属性存在默认值时,使用注解的时候可以不用传入属性值

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
    String value() default "都看到这里了,给个三连吧!";
}

当属性为数组,我们在使用注解传参时,如果数组里面只有一个内容,我们可以直接传入一个值,而不是创建一个数组

@Test("关注点了吗")
public static void main(String[] args) {
}
public class Main {
    @Test({"value1", "value2"})   //多个值时就使用花括号括起来
    public static void main(String[] args) {
    }
}

反射获取注解

我们的注解可以保留到运行时,使用反射机制来获取我们编写的注解:

public static void main(String[] args) {
    Class<Student> clazz = Student.class;
    for (Annotation annotation : clazz.getAnnotations()) {
        System.out.println(annotation.annotationType());   //获取类型
        System.out.println(annotation instanceof Test);   //直接判断是否为Test
        Test test = (Test) annotation;
        System.out.println(test.value());   //获取我们在注解中写入的内容
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值