- 各大框架都使用了很多注解,学习注解可以让我们更好的了解框架的运行原理
- 一般公司自己会封装一些注解,了解注解的原理可以让我们获得更高效的开发
- 掌握注解,我们可以有机会参与到公司框架的封装,得到个人能力的提升
一、什么是注解
Annotation
的作用:- 注解不是程序本身,但是它可以对程序做出解释(这点和
comment
相同) - 注解可以被其它程序(例如编译器)读取
- 注解不是程序本身,但是它可以对程序做出解释(这点和
Annotation
的格式:- 注解是以"@注释名"在代码中存在的
- 还可以添加一些参数值,例如:
@SuppressWarnings(value="unchecked")
Annotation
在哪里可以使用?- 可以用在
packge
、class
、method
、field
等上面,相当于给它们添加了额外信息 - 我们可以通过反射的机制来实现对这些元数据的访问
- 可以用在
二、内置注解
@Override
- 只适用于修饰方法,表示一个方法声明打算重写超类中的方法
@Deprecated
- 可以用于修饰方法、属性、类
- 表示这个方法已经过时,可以使用但是不建议使用
@SuppressWarnings
- 用来抑制编译时的警告信息
- 这个注解需要添加参数才能正常使用
@SuppressWarnings("all")
@SuppressWarnings("unchecked")
@SuppressWarnings(value={"unchecked","deprecated"})
- 其它。。。
/**
* @Title: 内置注解测试
* @Description:
* @author: QianYi
* @date: 2020/10/19 - 21:23
*/
public class AnnotationTest1 {
@Override // 表示方法的重写
public String toString() {
System.out.println("test @Override");
return "test @Override";
}
@Deprecated // 方法过时了,可以使用但是不建议使用
public static void testDeprecated() {
System.out.println("test @Deprecated");
}
@SuppressWarnings("all") // 抑制警告,可以传递相关参数
public void testSuppressWarnings() {
ArrayList<Object> list = new ArrayList<>();
}
public static void main(String[] args) {
testDeprecated();
}
}
三、元注解
- 元注解的作用:负责注解其它的注解
Java
中定义了4个标准的meta-annotation
(元注解)类型,分别是@Target
:用于描述注解可以用在什么地方
public @interface Target {
ElementType[] value();
}
//------------------------------------------------------------------------
public enum ElementType {
// 类、接口、枚举类
TYPE,
// 属性
FIELD,
// 方法
METHOD,
// 参数
PARAMETER,
// 构造器
CONSTRUCTOR,
// 局部变量
LOCAL_VARIABLE,
// 注释类型
ANNOTATION_TYPE,
// 包
PACKAGE,
// 参数类型
TYPE_PARAMETER,
// 使用类型
TYPE_USE
}
@Retention
:用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
// -----------------------------------------------
public enum RetentionPolicy {
// 源码
SOURCE,
// class文件
CLASS,
// 运行
RUNTIME
}
@Document
:表示该注解将被包含在javadoc
中@Inherited
:表示子类继承父类中的该注解
四、自定义注解
- 使用
@interface
自定义注解时,就自动继承了java.lang.annotation.Annotation
接口 - 分析
@interface
用来声明一个注解,其格式为
public @interface 注解名{
注解的内容
}
- 其中的每个方法其实就是声明了一个配置参数,方法名就是参数名,方法的返回值类型就是参数类型(只能是基本类型、Class、String、Enum)
- 可以通过
default
来声明参数的默认值 - 如果只有一个参数成员,一般将其命名为
value
- 注解元素必须要有值,在定义注解元素时,经常使用
空字符串
、0
作为默认值
package AnnotationAndReflect.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Title: 测试自定义注解
* @Description:
* @author: QianYi
* @date: 2020/10/19 - 22:04
*/
public class AnnotationTest2 {
// 显示的定义值,不写就是使用默认值(default)
@MyAnnotation01(name = "qy", age = 22, id = 1, schools = {"安徽大学"})
public void test() {
}
//只有一个参数时,默认名字一般是value,可省略不写
@MyAnnotation02("qy 666")
public void test2() {
}
}
/**
* 自定义注解01
*/
@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation01 {
//参数类型、参数名、默认值
String name() default "";
int age() default 0;
int id() default -1;
String[] schools() default {"清华大学", "北京大学"};
}
/**
* 自定义注解02
*/
@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation02 {
String value();
}
五、通过反射获取注解
/**
* 表名注解
*/
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@interface TableQY {
String value();
}
//-----------------------------------------------------------------------------------------
/**
* 属性注解
*/
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldQY {
String columnName();// 列名
String type(); // 类型
int length(); // 长度
}
//------------------------------------------------------------------------------------------
@TableQY("db_student")
class Student {
@FieldQY(columnName = "db_id", type = "int", length = 10)
private int id;
@FieldQY(columnName = "db_name", type = "String", length = 32)
private String name;
@FieldQY(columnName = "db_age", type = "int", length = 10)
private int age;
// get()、set()方法
// toString()方法
}
//-------------------------------------------------------------------------------------------
public class GetAnnotationByReflect {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
// 通过反射获取类对象
Class<?> clazz = Class.forName("AnnotationAndReflect.Annotation.Student");
// 一、
// 获取类注解
Annotation[] clzzAnnotations = clazz.getAnnotations();
System.out.println("类注解 : " + clzzAnnotations);
// 获取类注解的value
TableQY TableQYAnnotation = (TableQY) clazz.getAnnotation(TableQY.class);
System.out.println("类注解value : " + TableQYAnnotation.value());
// 二、
// 获取类属性注解
Field field = clazz.getDeclaredField("id");
// 获取类属性注解的value
FieldQY fieldAnnotation = field.getAnnotation(FieldQY.class);
System.out.println("属性注解value : \t"
+ fieldAnnotation.columnName() + "\t"
+ fieldAnnotation.type() + "\t"
+ fieldAnnotation.length());
}
}
运行结果:
参考信息
- https://www.bilibili.com/video/BV1p4411P7V3 【狂神说Java】注解和反射