代码改变世界

java Annotation注解使用

2023-03-17 22:05  youxin  阅读(37)  评论(0编辑  收藏  举报

Java注解用于为Java代码提供元数据。

元数据是指用来描述数据的数据,通俗一点,就是描述代码间关系,或者代码与其它资源(例如数据库表)之间内在联系的数据。在一些技术框架中,如Struts、hibernate就不知不觉用到了元数据。对于Struts来说,元数据指的是struts-config.xml;对hibernate来说就是hbm文件。以上阐述的几种元数据都是基于xml文件的或者其他形式的单独配置文件。这样表示有些不便之处。1、与被描述的文件分离,不利于一致性的维护;2、所有这样的文件都是ASCII文件,没有显式的类型支持。基于元数据的广泛使用,JDK5.0引入了Annotation的概念来描述元数据。在Java中,元数据以标签的形式存在于Java代码中,元数据标签的存在并不影响程序代码的编译和执行。简而言之,言而总之,注解就是标签的意思。

1. 注解的本质
java.lang.annotation.Annotation 接口中有这么一句话,用来描述『注解』:

The common interface extended by all annotation types
所有的注解类型都继承自这个普通的接口(Annotation)
 
这句话有点抽象,但却说出了注解的本质。我们看一个 JDK 内置注解的定义:

 

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

 


 
这是注解 @Override 的定义,其实它本质上就是:

 

public interface Override extends Annotation{    
}

 


注解的本质就是一个继承了 Annotation(注解) 接口的接口。

2. 注解是针对Java编译器的说明
注解,Annotation是JDK5.0引入的新技术。
注解的格式:@注释名,还可以添加参数(必要时)
注解不是程序本身,但可以对程序作出解释(就这一点,注释和注解的作用类似)
注解可以被其他程序读取(比如编译器等等)
注解可以给Java包、类型(类、接口、枚举)、构造器、方法、域、参数和局部变量进行注解,相当于给它们添加了一些额外的辅助信息。Java编译器可以根据指令来解释注解和放弃注解,或者将注解放到编译后的生成的class文件中,运行时可用。通过反射机制编程实现对这些元数据的访问。
一个注解准确意义上来说,只不过是一种特殊的注释而已,如果没有解析它的代码,它可能连注释都不如。注解只是元数据,不包含任何业务逻辑。

@interface 用来声明 Annotation,

 

注解的属性

 

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

 

@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 {
}

 

需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。

注解中属性可以有默认值,默认值需要用 default 关键值指定。比如:

 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
    public int id() default -1;
    public String msg() default "Hi";
}

 

TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi。
它可以这样应用。

 

@TestAnnotation()
public class Test {}

 

因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略。

另外,还有一种情况。如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。

 

public @interface Check {
    String value();
}

 

上面代码中,Check 这个注解只有 value 这个属性。所以可以这样应用。

 

@Check("hi")
int a;

 

这和下面的效果是一样的

 

@Check(value="hi")
int a;

 

最后,还需要注意的一种情况是一个注解没有任何属性。比如

 

public @interface Perform {}

 

那么在应用这个注解的时候,括号都可以省略。

 

@Perform
public void testMethod(){}

 

内置的注解

Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。

作用在代码的注解是

  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。

作用在其他注解的注解(或者说 元注解)是:

  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)

从 Java 7 开始,额外添加了 3 个注解:

  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

 

 

自定义注解
当我们理解了内置注解, 元注解和获取注解的反射接口后,我们便可以开始自定义注解了。

创建自定义注解和创建一个接口相似,但是注解的interface关键字需要以@符号开头,我们可以为注解声明方法。

自定义注解格式:

// 元注解
public @interface 注解名称{
// 属性列表
}
我们先来看看注解的例子:

 

1.创建自定义注解
/**
 * 自定义注解例子
 *
 * @author mikechen
 */

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface HelloAnnotation {
    String value();
}

 

2.使用自定义注解
/**
 * 使用自定义注解
 *
 * @author mikechen
 */
public class HelloAnnotationClient {
    @HelloAnnotation(value="Simple custom Annotation example")
    public void sayHello(){
        System.out.println("Inside sayHello method..");
    }
}

 

3.测试自定义注解
/**
 * 自定义注解测试
 *
 * @author mikechen
 */
public class HelloAnnotationTest {
    public static void main(String[] args) throws Exception {
        HelloAnnotationClient helloAnnotationClient=new HelloAnnotationClient();
        Method method=helloAnnotationClient.getClass().getMethod("sayHello");
        if(method.isAnnotationPresent(HelloAnnotation.class)){
            HelloAnnotation helloAnnotation=method.getAnnotation(HelloAnnotation.class);
            //Get value of custom annotation
            System.out.println("Value : "+helloAnnotation.value());
            //Invoke sayHello method
            method.invoke(helloAnnotationClient); }
            }
}

 

https://zhuanlan.zhihu.com/p/37701743

、注解通过反射获取

首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解。

public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}

2、getAnnotations() 方法

public Annotation[] getAnnotations() {}

前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。

https://zhuanlan.zhihu.com/p/513796089