注解概念理解参考:https://blog.csdn.net/briblue/article/details/73824058
https://blog.csdn.net/deskDopa/article/details/82557537
理解:
通俗的说,注解就是标签
注解可以在类加载,编译,运行时读取
自定义注解时,以@interface修饰符定义
Annotation接口是所有注解的父接口
在说注解之前,先说5个元注解!
一.5个元注解(对注解进行标记的标签,即注解的注解):
1.@Retention——注解生存期
取值如下:
RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
2.@Target——注解使用范围
注意:取值可以为数组,
@Target(value = {ElementType.FIELD, ElementType.METHOD})
单个值,
@Target(ElementType.FIELD)
取值如下:
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
3.@Documented——注解添加到API文档
4.@Inherited——在子类未使用注解的情况,将父类注解继承到子类 (就是让使用注解的类,在子类注解仍然起作用)
5.@Repeatable——重复注解,注解的值可以同时取多个 (注意:写该元注解来注解注解时,不要使用其他元注解)
@interface Persons { //注解值容器
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist") //取三个值
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
二.5个基本注解和自定义注解(基本注解是JDK已提供的):
1.@Override——标记方法重写
适用对象:方法
作用:主要可以检查编辑错误
2.@Deprecated——标记过时
适用对象:类,方法
3.@SuppressWarnings——阻止编译器警告
适用对象:所有
使用:@SuppressWarnings("unchecked") ,关键字使用:
all | 取消所有警告 |
boxing | 禁止与装箱/拆箱操作相关的警告 |
cast | 禁止与强制转换操作相关的警告 |
dep-ann | 禁止与废弃注释相关的警告 |
deprecation | 禁止与弃用相关的警告 |
fallthrough | 禁止与switch语句中丢失的中断相关的警告 |
finally | 要抑制相对于最终阻塞的不返回的警告 |
hiding | 抑制相对于隐藏变量的局部变量的警告 |
incomplete-switch | 要禁止与switch语句中丢失的条目相关的警告(enum情况) |
nls | 禁止与非nls字符串文字相关的警告 |
null | 抑制与空分析相关的警告 |
rawtypes | 在类参数上使用泛型时,禁止与非特定类型相关的警告 |
restriction | 禁止使用与禁止引用相关的警告 |
serial | 要禁用与可序列化类缺少serialVersionUID字段相关的警告 |
static-access | 禁止与不正确的静态访问相关的警告 |
synthetic-access | 禁止与内部类的未优化访问相关的警告 |
unchecked | 抑制与未检查操作相关的警告 |
unqualified-field-access | 禁止与字段访问无关的警告 |
unused | 抑制与未使用代码相关的警告 |
4.@ SafeVarargs——参数安全注解(“堆污染”警告):比如:泛型堆污染,将不带泛型的对象赋给带泛型的对象
还有一种消除堆污染方式:@SuppressWarnings("unchecked")
5.@FunctionInterface——函数式接口注解
函数式接口(只有一个抽象方法的接口)
作用:告诉编译器检查接口为函数式接口,编程时可以转化为Lambda表达式
自定义注解:定义注解时定义注解参数,使用注解时确定参数值
注解分为:
(
1.标识注解:就是定义注解没有参数(成员变量),比如@Override,@Deprecated...
2.元数据:定义注解包含参数(成员变量)(若参数只有一个,只能命名value())
)
package com.hw.writeannotion;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface CustomAnnotation{
//定义注解参数:注解参数类型 + 注解参数名();
//有默认值,在使用注解时可以不赋值
String name() default "我是默认";
int age() default 100;
}
package com.hw.writeannotion;
@CustomAnnotation(name = "pp",age = 20)
class Test {
}
可以,注解定义好了,而且使用了,可是不能生效。!!!
这需要相关工具提取并处理注解信息
三.提取注解信息:
提取注解信息,需要通过Java5在Javalang.reflect包新增的AnnotatedElement接口的实现类(Class,Constructor,Field,Method,Package)来提取信息。
AnnotatedElement接口:
AnnotatedElement接口实现方法:
判断该对象是否应用了某个注解:
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
获取该对象的指定类型注解:
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
获取该对象的所有注解:
public Annotation[] getAnnotations() {}
获取指定程序元素的注解:
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
获取指定程序元素的所有注解:
Annotation[] getDeclaredAnnotations() {}
获取@Repeatable重复注解下的注解:
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
获取@Repeatable重复注解下的所有注解:
<T extends Annotation> T[] getDeclaredByType(Class<T> annotationClass)
但是,要使用这些实现类的方法,必须通过反射获取对象!
实例:
提取元数据信息name,age:
package com.hw.writeannotion;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) //最好自定义注解时把可能用到的元注解都加上,避免获取不到注解
@Target(ElementType.METHOD)
@Documented
public @interface CustomAnnotation{
String name() default "我是默认";
int age() default 100;
}
package com.hw.writeannotion;
public class Test {
@CustomAnnotation(name = "pp",age = 20)
public void info() {
}
}
//提取注解信息
package com.hw.writeannotion;
import java.lang.annotation.Annotation;
public class MainTest {
public static void main(String[] args) throws NoSuchMethodException {
boolean b = Test.class.getMethod("info").isAnnotationPresent(CustomAnnotation.class);
if (b){
Annotation[] t = Test.class.getMethod("info").getAnnotations();
for (Annotation tt: t) {
if (tt instanceof CustomAnnotation)
System.out.println(((CustomAnnotation) tt).name());
System.out.println(((CustomAnnotation) tt).age());
}
}
}
}
结果:
pp
20
提取注解信息更多参考:
@TestAnnotation(msg="hello")
public class Test {
@Check(value="hi")
int a;
@Perform
public void testMethod(){}
@SuppressWarnings("deprecation")
public void test1(){
Hero hero = new Hero();
hero.say();
hero.speak();
}
public static void main(String[] args) {
boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
if ( hasAnnotation ) {
TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
//获取类的注解
System.out.println("id:"+testAnnotation.id());
System.out.println("msg:"+testAnnotation.msg());
}
try {
Field a = Test.class.getDeclaredField("a");
//我们不能直接操作私有属性,需要关闭程序安全检测
a.setAccessible(true);
//获取一个成员变量上的注解
Check check = a.getAnnotation(Check.class);
if ( check != null ) {
System.out.println("check value:"+check.value());
}
Method testMethod = Test.class.getDeclaredMethod("testMethod");
if ( testMethod != null ) {
// 获取方法中的注解
Annotation[] ans = testMethod.getAnnotations();
for( int i = 0;i < ans.length;i++) {
System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
}
}
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
结果:
id:-1
msg:hello
check value:hi
method testMethod annotation:Perform
注解实践: