Java注解
Java注解
author: histonevon@zoho
date: 09/03/2021
[TOC]
概念
- 注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明、注释。
- 概念描述
- JDK1.5之后的新特性
- 用于说明程序
- 使用方法:
@注解名称
- 作用分类
- 编写文档:通过代码里标识的注解生成文档【生成doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
- 分类
- JDK中预定义的一些注解
- 自定义注解
使用方法
JDK中预定义的一些注解
@Override
- 检测被该注解标注的方法是否是继承自父类(接口)的
@Deprecated
- 该注解标注的内容已过时
@SuppressWarning
- 压制警告
- 一般传递参数“all”,即
@SuppressWarnings("all")
package com.ices.annotation;
@SuppressWarnings("all")//压制所有警告
public class AnnotationDemo2 {
@Override
public String toString() {
return super.toString();
}
@Deprecated
public void show1(){
//有缺陷,过时处理
}
public void show2(){
//方法未使用,一般情况下会有警告
}
public void demo(){
show1();//因为过时,会被划掉,但仍然可以使用
}
}
自定义注解
格式
元注解
public @interface 注解名称{
属性列表;
}
本质
- 注解本质上就是一个接口,该接口默认继承
Annotation
接口
public interface MyAnnotation extends java.lang.annotation.Annotation {}
属性
-
接口中的抽象方法
-
要求
-
属性的返回值类型
- 基本数据类型
- String
- 枚举
- 注解
- 以删类型的数组
package com.ices.annotation; public enum Person { P1, P2; }
package com.ices.annotation; public @interface MyAnnotation2 { }
package com.ices.annotation; public @interface MyAnnotation { //不可用void、class等类型 int age(); String str(); Person p(); MyAnnotation2 myAnnotation2(); String[] strings(); }
-
定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
- 数组赋值时,值使用大括号包裹,如果数组中只有一个值,则大括号
{ }
可以省略
package com.ices.annotation; public @interface MyAnnotation { //不可用void、class等类型 int age(); String name() default "ZhangSan"; String str(); Person p(); MyAnnotation2 myAnnotation2(); String[] strings(); }
package com.ices.annotation; @MyAnnotation(age = 12, str = "xyz", p = Person.P1, myAnnotation2 = @MyAnnotation2, strings = {"abc", "def"}) public class AnnotationTest { }
-
元注解
- 用于描述注解的注解
@Target
- 描述注解能够作用的位置
ElementType
取值
取值 | 作用域 |
---|---|
TYPE | 可以作用于类上 |
METHOD | 可以作用于方法上 |
FIELD | 可以作用于成员变量上 |
@Retention
- 描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME)
:当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
@Documented
- 描述注解是否被抽取到api文档中
@Inherited
- 描述注解是否被之类继承
package com.ices.annotation;
import java.lang.annotation.*;
@Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})//表示该注解只能作用与类上
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MyAnnotation3 {
}
在程序中使用(解析)注解
-
获取注解中定义的属性值
- 获取注解定义的位置的对象(Class,Method,Field)
- 获取指定的注解
getAnnotation(Class)
,其实就是在内存中生成了一个该注解接口的值类实现对象,类似如下:
public class ProImpl implements Pro{ public String className(){ return "com.ices.domain.Person"; } public String methodName(){ return "eat"; } }
- 调用注解中的抽象方法获取配置的属性值
package com.ices.reflect;
import java.lang.reflect.Method;
@Pro(className = "com.ices.domain.Person", methodName = "eat")
public class ReflectTest2 {
public static void main(String[] args) throws Exception {
//1.解析注解
//1.1.获取该类的字节码文件对象
Class<ReflectTest2> reflectTest2Class = ReflectTest2.class;
//2.获取上边的注解对象
//其实就是在内存中生成了一个该注解接口的值类实现对象,类似如下:
/*
public class ProImpl implements Pro{
public String className(){
return "com.ices.domain.Person";
}
public String methodName(){
return "eat";
}
}
*/
Pro an = reflectTest2Class.getAnnotation(Pro.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();
String methodName = an.methodName();
System.out.println(className);
System.out.println(methodName);
//3.加载该类进内存
Class cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}
小结
- 以后大多数时候是使用注解,而不是自定义注解
- 注解给谁用:
- 编译器
- 解析程序
- 注解不是程序的一部分,可以理解为注解就是一个标签