java注解

注解:

从 JDK5 开始,Java 增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。SSM 项目中存在各种注解,因为后续会手写这几个框架,所有需要先打好基础,将这几个框架中要用到的知识点都去学习学习。

注解的定义:

注解通过 @interface 关键字定义的

 

public @interface LogAnnotation {String logValue() default "--";
}

 

注解的应用

上面创建了注解, 那么注解的使用

 

@LogAnnotation
public class Test {

}

 

元注解:

元注解标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

@Retention

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

它的取值如下:

RetentionPolicy.java

package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE,            /* Annotation 信息仅存在于编译器处理期间,编译器处理完之后就没有该 Annotation 信息了  */
CLASS,             </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 编译器将Annotation存储于类对应的.class文件中。默认行为  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

RUNTIME            </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 编译器将Annotation存储于class文件中,并且可由JVM读入 </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

}

 

 

 

 

@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {String logValue() default "--";
}

@Documented

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

@Target

ElementType.java
package java.lang.annotation;

public enum ElementType {
TYPE,
/ 类、接口(包括注释类型)或枚举声明 /

FIELD,              </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 字段声明(包括枚举常量)  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

METHOD,             </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 方法声明  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

PARAMETER,          </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 参数声明  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

CONSTRUCTOR,        </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 构造方法声明  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

LOCAL_VARIABLE,     </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 局部变量声明  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

ANNOTATION_TYPE,    </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 注释类型声明  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

PACKAGE             </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> 包声明  </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">

}

@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。

@Repeatable

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

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

注解的属性

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

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

/
 Annotation 类型里面的参数该怎么设定:
  第一, 只能用 public 或默认 (default) 这两个访问权修饰. 例如,String value(); 这里把方法设为 default 默认类型;   
  第二, 参数成员只能用基本类型 byte,short,char,int,long,float,double,boolean
八种基本数据类型和 String,Enum,Class,annotations 等数据类型, 以及这一些类型的数组.
例如: String value(); 这里的参数成员就为 String; 
*/
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {
/

logValue 表示调用 LogAnnotation 传递的参数名称为 logValue, String 表示传递的参数值为字符串
如: @LogAnnotation(logValue = "aaa")
*/
String logValue()
default "--";

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Integer time();  错误不能用包装数据类型</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> String time(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> public 可以省略, 因为默认是public权限</span>

}

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

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

@LogAnnotation(logValue = "进入 Animal 类", time = "2019-11-08")
public class Animal {
@LogAnnotation(logValue </span>= "调用name字段", time = "2019-01-01"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String name = "张三"<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Integer age = 19<span style="color: rgba(0, 0, 0, 1)">;

@LogAnnotation(logValue </span>= "调用sex字段", time = "2019-01-01"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String sex = "男"<span style="color: rgba(0, 0, 0, 1)">;

@LogAnnotation(logValue </span>= "调用eat方法", time = "2019-11-09"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> eat() {
    System.out.println(</span>"动物在吃饭"<span style="color: rgba(0, 0, 0, 1)">);
}

@LogAnnotation(logValue </span>= "调用sleep方法", time = "2019-11-10"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> sleep() {
    System.out.println(</span>"动物在睡觉"<span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> play() {
    System.out.println(</span>"动物在玩"<span style="color: rgba(0, 0, 0, 1)">);
}

}

需要注意的是,使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface 用来声明一个注

解,其中的每一个方法实际上是声明了一个属性。方法的名称就是属性的名称,返回值类型就是参数的类型(返回值类型只能是 8 种基本数据类型、Class、String、enum 及它们的数组)。

定义注解格式:

  public @interface 注解名 {定义体}

  注解参数的可支持数据类型:

    1. 所有基本数据类型(int,float,boolean,byte,double,char,long,short)

    2.String 类型

    3.Class 类型

    4.enum 类型

    5.Annotation 类型

    6. 以上所有类型的数组

private static void med3() throws NoSuchMethodException {Field[] declaredFields = Animal.class.getDeclaredFields();
        for (Field field : declaredFields) {
            LogAnnotation annotation = field.getAnnotation(LogAnnotation.class);
            if (annotation == null) {
                continue;
            }
            String logValue = annotation.logValue();
            String time = annotation.time();
            System.out.println(String.format("logValue=%s, time=%s", logValue, time));}
    }

结果:

logValue= 调用 name 字段, time=2019-01-01
logValue= 调用 sex 字段, time=2019-01-01