Java 注解用法

Java 注解用法

1、简述

Annontation是Java5开始引入的新特征。中文名称一般叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata) 与程序元素(类、方法、成员变量等)进行关联。

Annontation像一种修饰符样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

2、基本Annontation

  • java提供五个基础的annontation类型

    • @Override

      • 此注解作用于方法,作用于此方法的注解,意味此方法受重写规则的约束,否则不能编译成功

    • @Deprecated

      • 作用于方法,标注此方法过时

    • @SuppressWarnings

      • 对于某些不想看到的警告信息,可以通过这个注解来屏蔽

    • @SafeVarargs

      • 抑制类型转换异常的警告信息,只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。一个方法使用@SafeVarargs注解的前提是,开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题。

    • @FunctionalInterface

      • Java 8为函数式接口引入的一个新注解,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。保证该接口只能包含一个抽象方法

3、自定义注解

参考资料:https://www.jianshu.com/p/9471d6bcf4cf

4、getAnnotation方法

  • 获取作用于元素上的单个注解对象

4.1、获取类注解属性值

/**
* 自定义注解
*/
@Retention(RetentionPolicy.RUNTIME)//生命周期
@Target(ElementType.TYPE)//作用范围
public @interface Myannontation {
   String value();
}

/**
* 将自定义注解作用在People类
*/
@Myannontation("people")
public class People {

}

/**
* 测试类
*/
public class Test {

   public static void main(String[] args) throws ClassNotFoundException {
       //获取Class对象
       Class peopleClass=Class.forName("com.yl.annontation.People");
       //获取注解
       Myannontation myannontation= (Myannontation) peopleClass.getAnnotation(Myannontation.class);
       //获取注解值
       String value=myannontation.value();
       System.out.println(value);
  }

}

4.2、获取方法注解属性值

/**
* 自定义注解
*/
@Retention(RetentionPolicy.RUNTIME)//生命周期
@Target(ElementType.METHOD)//作用范围
public @interface Myannontation {
   String value();
}

/**
* 将自定义注解作用在show方法
*/

public class People {

   @Myannontation("show")
   public void show(){}
}

/**
* 测试类
*/
public class Test {

   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
       //获取Class对象
       Class peopleClass=Class.forName("com.yl.annontation.People");
       //获取show方法
       Method showMethod=peopleClass.getMethod("show");
       //获取注解
       Myannontation myannontation= (Myannontation) showMethod.getAnnotation(Myannontation.class);
       //获取注解值
       String value=myannontation.value();
       System.out.println(value);
  }

}

4.3、获取属性注解属性值

/**
* 自定义注解
*/
@Retention(RetentionPolicy.RUNTIME)//生命周期
@Target(ElementType.FIELD)//作用范围
public @interface Myannontation {
   String value();
}

/**
* 将自定义注解作用在属性
*/

public class People {
   @Myannontation("name")
   public String name;
}

/**
* 测试类
*/
public class Test {

   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException {
       //获取Class对象
       Class peopleClass=Class.forName("com.yl.annontation.People");
       //获取name属性
       Field nameField=peopleClass.getField("name");
       //获取注解
       Myannontation myannontation= (Myannontation) nameField.getAnnotation(Myannontation.class);
       //获取注解值
       String value=myannontation.value();
       System.out.println(value);
  }

}

5、getAnnotations方法

  • 获取作用于元素上的所有注解对象,包括父类注解

/**
*自定义注解1
*/
@Retention(value=RetentionPolicy.RUNTIME)//生命周期
@Target({ElementType.METHOD})//作用范围
@interface Anno{
//定义一个成员
String value();
}

/**
*自定义注解2
*/
@Retention(value=RetentionPolicy.RUNTIME)//生命周期
@Target({ElementType.METHOD})//作用范围
@interface Anno2{
//定义一个成员
String value();
}

/**
*将自定义注解作用在方法上
*/
class MyTest{
@Anno(value="张三")
@Anno2(value="李四")
public void info(){}
}

public class MainTest {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
//获取MyTest类的Class对象
Class<MyTest> myTestCls=(Class<MyTest>) Class.forName("getannotation方法使用.MyTest");
//获取info方法的对象
Method infoM=myTestCls.getMethod("info", null);
//获取作用于元素上的所有注解对象
Annotation[] annotatinArrays=infoM.getAnnotations();
//遍历annotatinArrays
for(Annotation annoObj:annotatinArrays){
if(annoObj instanceof Anno){
System.out.println("注解的元数据值="+((Anno)annoObj).value());
}else if(annoObj instanceof Anno2){
System.out.println("注解的元数据值="+((Anno2)annoObj).value());
}
}
}
   
}

6、isAnnotationPresent方法

  • 此方法判断元素是否作用注解,如果此方法作用于此注解,则返回true,否则返回false

/**
*自定义注解
*/
@Retention(value=RetentionPolicy.RUNTIME)//生命周期
@Target({ElementType.METHOD})//作用范围
@interface Anno{
//定义一个成员
String value();
}

/**
*自定义注解
*/
@Retention(value=RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@interface Anno2{
//定义一个成员
String value();
}

class MyTest{
public void info(){}

public void info2(){}

@Anno(value="张三")
public void info3(){}
}

public class MainTest {

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException {
//获取MyTest类的Class对象
Class<MyTest> myTestCls=(Class<MyTest>) Class.forName("getannotation方法使用.MyTest");
//获取info方法的对象
Method infoM=myTestCls.getMethod("info", null);
System.out.println(infoM.isAnnotationPresent(Anno.class));//fasle
}

}

7、getDeclaredAnnotations方法

  • 返回直接存在于此元素上的注解,即不包括从父类继承过来的注解。比较简单理解,不写代码案例了。

8、@Retention

@Retention是Java 1.8 才加进来的,所以算是一个新的特性

Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。

下面我们看一个人玩游戏的例子

/**一个人喜欢玩游戏,他喜欢玩英雄联盟,绝地求生,极品飞车,尘埃4等,则我们需要定义一个人的注解,他属性代表喜欢玩游戏集合,一个游戏注解,游戏属性代表游戏名称*/
/**玩家注解*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface People {
   Game[] value() ;
}

/**游戏注解*/
@Repeatable(People.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Game {
   String value();
}

/**玩游戏类*/
@Game(value = "LOL")
@Game(value = "PUBG")
@Game(value = "NFS")
@Game(value = "Dirt4")
public class PlayGame {
}

/**
*测试类,获取注解属性值
*/
public static void main(String[] args) throws ClassNotFoundException {
       //获取Class对象
       Class playClass=Class.forName("com.yl.annontation.PlayGame");
       //获取注解
       People people= (People) playClass.getAnnotation(People.class);
       //获取注解值
       Game[] value=people.value();
  //输出注解值
       System.out.println(Arrays.toString(value));
  }
/**
*@Game会存入@People的Game[]中
*@Game必须要有一个属性名为value,@People也是
*/

9、编译时处理Annotation

处于RetentionPolicy.CLASS生命周期的注解信息,如何提取?

问题就是当处理CLASS阶段的注解信息,会在运行期间之前就丢失,因此不能通过运行期间的反射机制提取数据

但是可以通过APT工具,在javac期间提取处于编译时的注解数据信息

具体如何实现

/**
*创建一个处于编译期间的注解
*/
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.TYPE)
public @interface MyAnno {
   String value();
}

/**
*注解作用于类
*/
@MyAnno(value="red apple")
public class Apple {}

@SupportedSourceVersion(SourceVersion.RELEASE_8)//设置jdk版本
@SupportedAnnotationTypes("apt.MyAnno") //设置自定义注解
public class MyAnnotationProcess extends AbstractProcessor {
   
   /**
   *重写核心方法:注解处理器,当javac调用apt工具触此处理器
   */
   @Override
   public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
       //获取根节点信息
       for (Element rootElement : roundEnv.getRootElements()) {
           //如果此根节点标注注解信息并且属于类
           if(rootElement.getKind()== ElementKind.CLASS) {
               //获取注解类对象
               MyAnno annTest=rootElement.getAnnotation(MyAnno.class);
               if(annTest!=null) {
                   System.out.println("将编译时的注解元 数据提取="+annTest.value());
              }
          }
      }
       return false;
  }
}

如何通过apt编译

  • javac -d . MyAnnotationProcess.java

  • javac -d . *.java -processor apt.MyAnnotationProcess

最终输出结果

 

记得快乐
原文地址:https://www.cnblogs.com/Y-wee/p/13528883.html