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, /* 编译器将Annotation存储于类对应的.class文件中。默认行为 */ RUNTIME /* 编译器将Annotation存储于class文件中,并且可由JVM读入 */ }
@Retention(RetentionPolicy.RUNTIME) public @interface LogAnnotation { String logValue() default "--"; }
@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Target
ElementType.java
package java.lang.annotation; public enum ElementType { TYPE, /* 类、接口(包括注释类型)或枚举声明 */ FIELD, /* 字段声明(包括枚举常量) */ METHOD, /* 方法声明 */ PARAMETER, /* 参数声明 */ CONSTRUCTOR, /* 构造方法声明 */ LOCAL_VARIABLE, /* 局部变量声明 */ ANNOTATION_TYPE, /* 注释类型声明 */ PACKAGE /* 包声明 */ }
@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 "--"; // Integer time(); 错误不能用包装数据类型 public String time(); // public 可以省略, 因为默认是public权限 }
上面代码定义了 @LogAnnotation 这个注解中拥有 logValue 和 time 两个属性。在使用的时候,我们应该给它们进行赋值。
赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开。
@LogAnnotation(logValue = "进入Animal类", time = "2019-11-08") public class Animal { @LogAnnotation(logValue = "调用name字段", time = "2019-01-01") public static final String name = "张三"; public static final Integer age = 19; @LogAnnotation(logValue = "调用sex字段", time = "2019-01-01") public static final String sex = "男"; @LogAnnotation(logValue = "调用eat方法", time = "2019-11-09") public void eat() { System.out.println("动物在吃饭"); } @LogAnnotation(logValue = "调用sleep方法", time = "2019-11-10") public void sleep() { System.out.println("动物在睡觉"); } public void play() { System.out.println("动物在玩"); } }
需要注意的是,使用@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