注解简介
注解:Annotation,也叫元数据。一种代码级别的说明,JDK 1.5 及以后版本引人的一个特性,与类、接口、枚举是在同一个层次。可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释
作用:
- 编写文档:通过代码里标识的注解生成文档(生成文档doc文档)
/** * @Author:Hefery * @Version:1.0.0 * @Date:2022/3/15 12:03 * @Description: */ public class AnnotationDemo { /** * 两数相加 * @param a 加数 * @param b 加数 * @return 和 */ public int add(int a, int b) { return a + b; } }
- 代码分析:通过代码里标识的注解对代码进行分析(使用反射)
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查(如@Override)
JDK预定义注解
作用在代码层面的注解
-
@Override:检查该方法是否是重写方法。果发现其父类,或是引用的接口中并没有该方法,报编译错误
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
-
@Deprecated:标记过时方法。如果使用该方法,会报编译警告
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
-
@SuppressWarnings:指示编译器去忽略注解中声明的警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
// @SuppressWarnings:指示编译器去忽略注解中声明的警告
@SuppressWarnings("all") // 会警告类中有未使用的方法,类上标注 @SuppressWarnings 就是要压住警告
public class AnnotationDemo {
// @Override:检查该方法是否是重写方法。果发现其父类,或是引用的接口中并没有该方法,报编译错误
@Override
public String toString() {
return super.toString();
}
// @Deprecated:标记过时方法。如果使用该方法,会报编译警告
@Deprecated
public void show1() {
// 有缺陷,建议使用 show2() 方法
// 不能删,要兼容使用到 show1() 方法
}
public void show2() {
// 替代 show1() 方法
}
public void showDemo() {
show1(); // 删除线提示该方法已过时或已弃用
show2();
}
}
作用在其他注解的注解—元注解
- @Retention:标识这个注解怎么保存。描述注解被保留的阶段,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); } public enum RetentionPolicy { /** * 源代码Source阶段 */ SOURCE, /** * 类对象 Class 阶段 */ CLASS, /** * 运行时Runtime阶段,自定义注解一般使用 */ RUNTIME }
- @Documented:标记这些注解是否包含在用户 API 文档中
- @Target:标记这个注解应该是哪种 Java 成员,能够作用的位置
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
- @Inherited:标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
/** 作用于类、接口、注解、枚举 */
TYPE,
/** Field declaration (includes enum constants) */
/** 作用于字段 */
FIELD,
/** Method declaration */
/** 作用于方法 */
METHOD,
/** Formal parameter declaration */
/** 作用于参数 */
PARAMETER,
/** Constructor declaration */
/** 作用于构造器 */
CONSTRUCTOR,
/** Local variable declaration */
/** 作用于本地变量 */
LOCAL_VARIABLE,
/** Annotation type declaration */
/** 作用于枚举 */
ANNOTATION_TYPE,
/** Package declaration */
/** 作用于包 */
PACKAGE,
/**
* Type parameter declaration
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
* @since 1.8
*/
TYPE_USE
}
从Java 7开始,新增的注解
- @SafeVarargs:Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告
- @FunctionalInterface:Java 8 开始支持,标识一个匿名函数或函数式接口
- @Repeatable:Java 8 开始支持,标识某注解可以在同一个声明上使用多次
自定义注解
了解注解本质
注解本质:默认继承 Annotation 类的接口
在 IDEA 编辑 HeferyAnnotation 注解:public @interface HeferyAnnotation {}
编译:javac HeferyAnnotation.java
,生成 .class 文件
反编译:javap HeferyAnnotation.class
,控制台输出public interface HeferyAnnotation extends java.lang.annotation.Annotation { }
注解属性定义
注解格式:
@元注解
public @interface 注解名称 {
// 属性列表
}
注解属性:接口中的抽象方法
注解属性要求:
- 返回值:基本数据类型、String、枚举、注解、以上类型的数组
- 使用:使用注解属性要给属性赋值
如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值
数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}省略
自定义注解:
@Documented // 标记这些注解是否包含在用户 API 文档中
@Target(value = {ElementType.TYPE, ElementType.METHOD}) //当前被描述注解作用于类、接口、注解、枚举+方法
@Retention(RetentionPolicy.RUNTIME) // 当前被描述的注解会保留到class字节码文件中,并被JVM读取到
public @interface HeferyAnnotation {
}
@HeferyAnnotation // @Target(value = {ElementType.TYPE, ElementType.METHOD})
public class Worker {
//@HeferyAnnotation // 报错:'@HeferyAnnotation' not applicable to field
public String workName;
@HeferyAnnotation
public void work() {
System.out.println("工人最有力量");
}
}
程序中使用注解
模拟注解想要调用 Demo 类的 show() 方法
public class Demo {
public void show() {
System.out.println("show Demo01 ...");
}
}
自定义注解
/**
* @Author:Hefery
* @Version:1.0.0
* @Date:2022/3/15 13:18
* @Description:描述需要执行的类名,和方法名
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertiesAnnotation {
String className();
String methodName();
}
使用注解实现调用 Demo 类的 show() 方法
@PropertiesAnnotation(className = "com.hefery.kafkademo.annotation.Demo", methodName = "show")
public class ReflectTest {
public static void main(String[] args) {
/**
* 不能改变该类的任何代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法
* 1. 反射:定义 .properties 文件去读取里面的内容,并封装到 Properties,通过反射将类加载至内存并 newInstance 创建对象,从而调用其方法
* 2. 注解:
*/
// 1. 解析注解:获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
// 2 获取注解对象:在内存中生成了一个该注解接口的子类实现对象
PropertiesAnnotation reflectTestClassAnnotation = reflectTestClass.getAnnotation(PropertiesAnnotation.class);
// 3 调用注解对象中定义的抽象方法(属性)
String className = reflectTestClassAnnotation.className();
String methodName = reflectTestClassAnnotation.methodName();
System.out.println(className); // com.hefery.kafkademo.annotation.Demo01
System.out.println(methodName); // show
}
}