写点什么

Java 注解 (1),headfirstjavapdf 百度云

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:4081 字

    阅读完需:约 13 分钟

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


它的取值如下:


  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。如 Java 内置注解,@Override、@Deprecated、@SuppressWarnning 等

  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。如 SpringMvc 中的 @Controller、@Autowired、@RequestMapping 等。

@Documented

顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Target

Target 是目标的意思,@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 注解,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。


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

@Repeatable

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


Repeatable 使用场景:在需要对同一种注解多次使用时,往往需要借助 @Repeatable。


下面举例说明一下,在生活中一个人往往是具有多种身份,如果我把每种身份当成一种注解该如何使用


先声明一个 Persons 类用来包含所有的身份


@Target(ElementType.TYPE)


@Retention(RetentionPolicy.RUNTIME)


public @interface Persons {


Person[] value();


}


这里 @Target 是声明 Persons 注解的作用范围,参数 ElementType.Type 代表可以给一个类进行注解


@Retention 是注解的有效时间,RetentionPolicy.RUNTIME 是指程序运行的时候。


Person 注解


@Repeatable(Persons.class)


public @interface Person{


String role() default "";


}


@Repeatable 括号内的就相当于用来保存该注解内容的容器。


声明一个 Man 类,给该类加上一些身份。


@Person(role="CEO")


@Person(role="husband")


@Person(role="father")


@Person(role="son")


public class Man {


String name="";


}


在主方法中访问该注解。


public static void main(String[] args) {


Annotation[] annotations = Man.class.getAnnotations();


System.out.println(annotations.length);


Persons p1=(Persons) annotations[0];


for(Person t:p1.value()){


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


}


}


运行结果


1


CEO


husband


father


son


注解的属性




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


@Target(ElementType.TYPE)


@Retention(RetentionPolicy.RUNTIME)


public @interface TestAnnotation{


int id();


String msg();


}


上面代码定义了 @TestAnnotation 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们应该给它们进行赋值。


赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开。


@TestAnnotation(id=3, msg="hello annotation")


public class Test {


}


快捷方式




所谓的快捷方式就是注解中定义了名为 value 的元素,并且在使用该注解时,如果该元素是唯一需要赋值的一个元素,那么此时无需使用 key=value 的语法,而只需在括号内给出 value 元素所需的值即可。这可以应用于任何合法类型的元素,记住,这限制了元素名必须为 value,简单案例如下


@Target(ElementType.FIELD)


@Retention(RetentionPolicy.RUNTIME)


@interface IntegerVaule{


int value() default 0;


String name() default "";


}


public class QuicklyWay {


@IntegerVaule(20)


public int age;


@IntegerVaule(value = 10000, name = "MONEY")


public int money;


}


[](ht


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


tps://blog.csdn.net/ThinkWon/article/details/100178709)注解不支持继承




注解是不支持继承的,因此不能使用关键字 extends 来继承某个 @interface,但注解在编译后,编译器会自动继承 java.lang.annotation.Annotation 接口


声明注解




这里总共定义了 4 个注解来演示注解的声明


  1. 定义一个可以注解在 Class,interface,enum 上的注解

  2. 定义一个可以注解在 METHOD 上的注解

  3. 定义一个可以注解在 FIELD 上的注解

  4. 定义一个可以注解在 PARAMETER 上的注解


@Target(ElementType.TYPE)


@Retention(RetentionPolicy.RUNTIME)


public @interface MyAnTargetType {


/**


  • 定义注解的一个元素 并给定默认值

  • @return


*/


String value() default "定义在类接口枚举类上的注解元素 value 的默认值";


}


@Target({ElementType.METHOD})


@Retention(RetentionPolicy.RUNTIME)


public @interface MyAnTargetMethod {


/**


  • 定义注解的一个元素 并给定默认值

  • @return


*/


String value() default "定义在方法上的注解元素 value 的默认值";


}


@Target({ElementType.FIELD})


@Retention(RetentionPolicy.RUNTIME)


public @interface MyAnTargetField {


/**


  • 定义注解的一个元素 并给定默认值

  • @return


*/


String value() default "定义在字段上的注解元素 value 的默认值";


}


@Target({ElementType.PARAMETER})


@Retention(RetentionPolicy.RUNTIME)


public @interface MyAnTargetParameter {


/**


  • 定义注解的一个元素 并给定默认值

  • @return


*/


String value() default "定义在参数上的注解元素 value 的默认值";


}


编写一个测试处理类处理以上注解


@MyAnTargetType


public class AnnotationTest {


@MyAnTargetField


private String field = "我是字段";


@MyAnTargetMethod("测试方法")


public void test(@MyAnTargetParameter String args) {


System.out.println("参数值 === " + args);


}


public static void main(String[] args) {


// 获取类上的注解 MyAnTargetType


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


System.out.println("类上的注解值 === " + t.value());


MyAnTargetMethod tm = null;


try {


// 根据反射获取 AnnotationTest 类上的 test 方法


Method method = AnnotationTest.class.getDeclaredMethod("test", String.class);


// 获取方法上的注解 MyAnTargetMethod


tm = method.getAnnotation(MyAnTargetMethod.class);


System.out.println("方法上的注解值 === " + tm.value());


// 获取方法上的所有参数注解 循环所有注解找到 MyAnTargetParameter 注解


Annotation[][] annotations = method.getParameterAnnotations();


for (Annotation[] tt : annotations) {


for (Annotation t1 : tt) {


if (t1 instanceof MyAnTargetParameter) {


System.out.println("参数上的注解值 === " + ((MyAnTargetParameter) t1).value());


}


}


}


method.invoke(new AnnotationTest(), "改变默认参数");


// 获取 AnnotationTest 类上字段 field 的注解 MyAnTargetField


MyAnTargetField fieldAn = AnnotationTest.class.getDeclaredField("field").getAnnotation(MyAnTargetField.class);


System.out.println("字段上的注解值 === " + fieldAn.value());


} catch (Exception e) {


e.printStackTrace();


}


}


}


输出结果


类上的注解值 === 定义在类接口枚举类上的注解元素 value 的默认值


方法上的注解值 === 测试方法


参数上的注解值 === 定义在参数上的注解元素 value 的默认值


参数值 === 改变默认参数


字段上的注解值 === 定义在字段上的注解元素 value 的默认值


Java 预置的注解




学习了上面相关的知识,我们已经可以自己定义一个注解了。其实 Java 语言本身已经提供了几个现成的注解。

@Deprecated

这个元素是用来标记过时的元素,想必大家在日常开发中经常碰到。编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量。

@Override

这个大家应该很熟悉了,用于标明此方法覆盖了父类的方法。

@SuppressWarnings

用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。之前说过调用被 @Deprecated 注解的方法后,编译器会警告提醒,而有时候开发者会忽略这种警告,他们可以在调用的地方通过 @SuppressWarnings 达到目的。

@SafeVarargs

参数安全类型注解。它的目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生 unchecked 这样的警告。它是在 Java 1.7 的版本中加入的。

@FunctionalInterface

函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式编程很火,所以 Java 8 也及时添加了这个特性。


函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。


我们进行线程开发中常用的 Runnable 就是一个典型的函数式接口,从源码可以看到它使用了 @FunctionalInterface 注解。


注解应用实例




注解的功能很强大,Spring 和 Hebernate 这些框架在日志和有效性中大量使用了注解功能。


注解通常配合反射或者切面一起使用来实现相应的业务逻辑。


我这里向大家演示使用注解和切面进行日志记录的案例


定义一个系统日志注解


@Target(ElementType.METHOD)


@Retention(RetentionPolicy.RUNTIME)


@Documented


public @interface SysLog {


/**


  • 操作说明


*/


String value() default "";


}


找到使用了注解的方法,利用切面进行日志记录


这里有些类或者参数只做演示,没有给出具体的实现(如 SysLogMapper、SysLogEntity 等),以看懂注解配合切面使用为目的


@Aspect


@Component

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Java注解(1),headfirstjavapdf百度云