云迈博客

您现在的位置是:首页 > 后端开发 > Java > 正文

Java

java中的注解

黄蓉蓉2022-07-31Java24
​一、概念注解是插入到源代码中的标记,并且可以使用其他工具(程序)对其进行处理。这些工具可以在源码层次上进行操作,或者可以处理由编译器放置了注解的类文件(.class)。

一、概念

  注解是插入到源代码中的标记,并且可以使用其他工具(程序)对其进行处理。

  这些工具可以在源码层次上进行操作,或者可以处理 由编译器放置了注解的类文件(.class)。

  注解是源代码的一部分,但不会改变程序的编译方式,编译器对于包含注解和不包含注解的代码会生成相同的虚拟机指令。

二、应用场景及好处

 应用广泛,很多工具或者说框架的编写者都会让使用者采用注解的形式,例如测试框架JUnit等

  对于处理工具/框架的使用者来说,注解语法更加简洁友好。

三、注解分类

1、 元注解:系统已经定义好的,注解在注解接口上 

              (1)  @Target  :限制注解可以应用到哪些目标元素,元素类型是ElementType枚举型

@Target注解的元素类型
元素类型(在ElementType中定义) 注解应用场合
ANNOTATION_TYPE 注解类型声明
PACKAGE 包
TYPE 类
METHOD 方法
CONSTRUCTOR 构造方法
FIELD 成员变量
PARAMETER 方法或构造方法的参数
LOCAL_VARIABLE 局部变量
(2) @Retention :指定注解保存的时间

@Retention的保留策略
保留规则 描述
SOURCE 源文件(.java)
CLASS 包括在类文件中(.class),但是虚拟机不需要将它们载入
RUNTIME 包括在类文件中(.class),并由虚拟机载入。通过反射机制可获得定义的注解
(3) @Documented : 是否将注解保存到javadoc中

               (4) @Inherited :         声明注解可以被子类继承

2、标准注解 

     (1) 用于编译的注解

     (2) 用于资源管理的注解       

3、自定义注解

四、定义注解

 每个注解都必须通过一个注解接口进行定义,这些接口中的方法与注解中的元素(属性)相对应。     

语法:

访问修饰符 @interface 注解名{

     方法返回值     方法名()     default  元素(属性)的默认值;

     //属性值类型    属性名      属性的默认值

}

例如,我们写一个工具来在控制台打印某个类的详细信息,来模拟某些API框架。

在定义注解的时候,我们有必要思考的有:注解的功能、注解的作用在哪个位置、注解中有什么元素(属性)及元素的类型。

定义描述类的注解接口:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) //限定@API注解只能用于类型上
@Retention(RetentionPolicy.RUNTIME) //保留在运行时,为了方便处理程序能通过反射机制获得@API注解
public @interface API {

/**
 * 类描述
 * @return
 */
String value() default "";

}

定义描述对象字段的注解接口:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Property {
/**

 * 字段类型
 * @return
 */
String type() default "";
/**
 * 字段名字
 * @return
 */
String name() default "";
/**
 * 字段默认值
 * @return
 */
String defaultValue() default "";
/**
 * 字段描述
 * @return
 */
String description() default "";

}

  注意事项:

  1、注解接口中的方法不能有形参

  2、方法的返回值(元素类型)可以是基本类型、String、Class、枚举类型、注解类型和它们的数组类型

  3、default是关键字,用来指定元素的默认值,默认值不能设置为null,可以设置成""或者"none"或者Void.class

  4、@interface声明创建了一个真正的java接口。处理注解的工具将接收那些实现了这个注解接口的对象。

四、使用注解

在使用注解时,应该考虑的问题有:注解有哪些元素、注解的功能、注解作用在哪些位置上。

在java中,注解是当作一个修饰符来使用的,使用@注解名字

例如,用户类对象

@API(“用户”)
public class User {

@Property(type="Number",description="账号")
private Integer id = 1;

@Property(description="用户名")
private String name = "Herrona";

@Property(description="密码")
private String pwd = "1234";

@Property(type="Number",description="年龄")
public int age = 20;

}

使用注解时的注意事项:

(1) 元素没有顺序

(2) 如果只使用value属性,则可以省略value属性的名字

(3) 如果不使用注解中的属性,则可以省略注解括号,这样的注解称为标记注解

五、注解处理工具(注解处理程序)

 前面说过,注解通过注解接口来定义的,接口只是抽象的描述和约定,并不会帮我们实现功能。

 所以我们还必须写注解处理程序来实现我们需要的功能。

 处理程序可以通过反射机制获得类、字段、方法和注解等的信息。

import java.lang.reflect.Field;

/**

  • 注解处理类

  • @author Herrona
    */
    public class ApiPrinter {

    /**

    • 在控制台打印成表格
    • @param obj
    • @throws IllegalAccessException
    • @throws IllegalArgumentException
      */
      public static void print(Object obj) throws IllegalArgumentException, IllegalAccessException {
      Class<?> c = obj.getClass();
      API api = c.getAnnotation(API.class);
      if (api != null) {
       System.out.printf("%s <%s> 详情:\n",api.value(),c.getTypeName());
       System.out.println("--------------------------------------------------------------");
       System.out.printf("字段名\t\t字段类型\t\t默认值 \t\t描述\n");
       System.out.println("--------------------------------------------------------------");
       // 遍历属性
       for (Field f : c.getDeclaredFields()) {
           // 获得属性上的Property注解对象
           Property p = f.getAnnotation(Property.class);
           // 如果该属性使用了Property注解对象
           if (p != null) {
               f.setAccessible(true);
               String name = p.name();
               String type = p.type();
               String defaultType = p.defaultValue();
               String desc = p.description();
               if(name.equals(""))
                   name = f.getName();
               if(type.equals(""))
                   type = f.getType().getSimpleName();
               if(defaultType.equals(""))
                   defaultType = f.get(obj).toString();
               System.out.printf("%s\t\t%s\t\t%s\t\t%s", 
                       name, type,defaultType,desc);
               System.out.println();
           }
       }
       System.out.println("--------------------------------------------------------------");
      }
      }
      }

六、测试 六、测试

   调用处理程序的方法,在控制台打印对象信息。

public class Test {

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
    ApiPrinter.print(new User());
}

}

发表评论

评论列表

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~