一文学懂JAVA之注解篇

 Hygge   2021-04-17 07:43   79 人阅读  0 条评论

第六章 注解

6.1 注解

  • 注解(annotation) : 是一种代码级别的说明,和类、接口平级关系

    • 注解(annotation) : 相当于一种标记,在程序中加入注解就等于为程序打上某种标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无标记,看你的程序有什么标记,就区看相应的事。

    • 我们之前使用过的注解:

    1. @Override : 子类重写方法时----编译时起作用

    2. @FunctionalInterface:函数式接口----编译时起作用

    3. @Test JUnit: 测试注解----运行时起作用

注解的作用:

  • 生成帮助文档:@author 和 @version

  • 执行编译器的检查 例如:@Override

  • 框架的配置(框架 = 代码 + 配置)

6.2 三个基本注解

注解名描述
@Override描述方法的重写
@SuppressWarnings压制\忽略警告
@Deprecated标记过时

@Override示例代码:

public class Person {
   public void eat(){
       System.out.println("吃饭饭");
   }
}

class Student extends Person{
   // Override 标明重写父类方法的注解
   @Override
   public void eat() {
       super.eat();
   }
}

@SuppressWarnings : 压制\忽略警告信息

1618470009245.png

对于 只声明未使用过的变量或方法会有默认的警告信息,可以使用@SuppressWarnings来压制警告信息

@SuppressWarnings("all")
public class Person{
   public void eat(){
       int num = 5;
   }
}

@Deprecated:标记已过时

1618470185770.png

适用于方法仍可使用,但是不建议使用,未来将要移除该方法的场景

6.3 自定义注解


自定义注解语法

public @interface 注解名{
    属性
}
// 定义一个注解
public @interface Annotation01 {
   
}


注解属性

  1. 基本类型

  2. String

  3. Class类型

  4. 注解类型

  5. 枚举类型

  6. 以上类型的一维数组类型

示例代码:

public @interface mAnnotation1 {
//    1.基本数据类型(4类8种)
   int i1();
   double d1();

//    2.String类型
   String str();

//    3.Class类型
   Class c1();

//    4.注解类型,自定义的注解
   testAnnotation ann1();

//    5.枚举类型,自定义的枚举类型
   Gender sex();

//    6.以上类型的一维数组类型
   int[] gs();
   double[] hs();
   String[] iss();
   Gender[] sexs();
   testAnnotation[] anns();
}


使用自定义注解

1618475664514.png

/*
使用注解:
 没有属性的注解:直接使用即可,@注解名  或者  @注解名()
 有属性的注解:使用有属性的注解的时候一定要给注解属性赋值
 给属性赋值的格式:
  @注解名(属性名=属性值,属性名=属性值)
  ps:对于数组初始化赋值不能使用new,必须使用{}进行赋值
*/


使用注解的注意事项

  1. 一旦注解有了属性,使用注解的时候,属性必须有值

  2. 若属性类型是一维数组的时候,当数组的值只有一个的时候可以忽略{}

  3. 如果注解中只有一个属性,并且属性名为value,那么使用直接给注解属性赋值的时候,注解属性名value可以省略

  4. 注解属性可以有默认值:属性类型 属性名() default 默认值;


6.4 元注解

什么是元注解?

定义在注解上的注解

常见的元注解

  • Target : 表示该注解作用在什么上面(位置),默认注解可以放在任何位置。值为ElementType的枚举值

    METHOD : 方法

    TYPE : 类 接口

    FIELD : 字段

    MODULE : 在模块上使用

  • Retention : 定义该注解保留到哪个代码阶段,值为:RetentionPolicy的枚举值,默认是只在源码阶段保留

    SOURCE : 只在源码上保留(默认)

    CLASS : 在源码和字节码上保留

    RUNTIME : 在所有阶段都保留

.java (源码阶段)  ---  编译   --->  .class(字节码阶段)  --- 加载内存  ---- 运行(RUNTIME)

// 标准格式:
//@Target(value={ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.LOCAL_VARIABLE})
//@Retention(value= RetentionPolicy.RUNTIME)
   // 省略格式
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {// 默认该注解可以在任何位置使用

}

6.5 注解解析

之前自定义的注解都是没有实际功能的,要实现实际功能需要进行注解解析

java.lang.reflect.AnnotatedElement接口:Class、Method、Field、Constructor等实现了AnnotatedElement

方法(两个方法的参数都是 注解的class对象)描述
T getAnnotation(Class<T> annotationType)得到指定类型的注解引用,没有返回null
boolean isAnnotationPresent(Class<? extends Annotation> annotationType)判断指定的注解有没有

通过getAnnotation得到的注解对象可以通过对象.属性名来获取值

测试的注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface mAnnotation1 {
   int i1();
   String[] strs();
}

测试的主类:

       Class<Person> personClass = Person.class;
       Method eat = personClass.getDeclaredMethod("eat");

//        标记方法是否有指定的注解
       boolean ans = eat.isAnnotationPresent(mAnnotation1.class);
//        获取方法上的注解对象
       mAnnotation1 annotation = eat.getAnnotation(mAnnotation1.class);

       System.out.println(annotation.i1());
       System.out.println(Arrays.toString(annotation.strs()));

6.6 模拟JUnit实现

需求

在一个类(测试类,TestDemo)中有三个方法,其中两个方法上有@MyTest

另一个没有.还有一个主测试类(MainTest)中有一个main方法.  

在main方法中,让TestDemo类中含有@MyTest方法执行.   自定义@MyTest, 模拟单元测试.

思路分析

  1. 定义两个类和一个注解

  2. 在MainTest的main()方法里面:

    //1.获得TestDemo字节码对象 //2.反射获得TestDemo里面的所有的方法 //3.遍历方法对象的数组. 判断是否有@MyTest(isAnnotationPresent) //4.有就执行(method.invoke())

代码实现

1618487088408.png


本文地址:https://blog.lisok.cn/post/38.html
版权声明:本文为原创文章,版权归 Hygge 所有,欢迎分享本文,转载请保留出处!

 发表评论


表情

还没有留言,还不快点抢沙发?