java中常见的注解@Override:作用在方法上的注解。当方法不是重写父类的方法时会报错;(这个注解可以帮我们检查覆盖是否正确。覆盖时推荐必须使用这个,增强阅读性。由于这个注解在运行时没啥作用,所以它的保留策略用SOURCE(只在源码中存活)级别的就行)
@Deprecated:作用在方法上。标记该方法为作废方法(已过时);
@SuppressWarnings:作用在方法上,压制警告。
如何自定义注解类
使用 @interface代替class,interface,enum,和这三个是同一级别的(看反编译后的文件可以知道,注解类其实是个继承了Annotation的接口)
注解类中定义属性(看代码时更像是抽象方法,毕竟是个接口类)
String类 , 8种基本数据类型,Class类,enum类,注解类+参数名+ ()
如果有默认值,则在() 后面加 :default 对应的值(这样,使用时就可以使用默认值了,就可以不写它了)
例子(带默认值): String name() default "小强";
注解的作用和怎么使用代替xml配置文件
定义注解类:框架的工作
使用注解:我们的工作
读取注解(反射):框架的工作
限定注解类的使用区域和存活环境的注解(元注解):
1、限定注解的使用区域注解:@Target:
属性成员:只有一个名为value的枚举类型数组value常见的可选值及其含义:ElementType.TYPE(只能给类,接口,枚举类上注解)
ElementType.FILED(给类属性(字段)上注解)
ElementType.METHOD(方法上注解)
ElementType.PARAMETER(方法的参数上注解)
ElementType.CONSTRUCTOR(给构造器上注解)
ElementType.LOCAL_VARIABLE(给局部变量上注解)
2、限定注解的存活环境注解(保留策略):@Retention:属性成员:只有一个名为value的枚举类型
value常的可选值及其含义:RetentionPolicy.SOURCE(只在源码中存活,一旦变为class文件,注解就消失了)
RetentionPolicy.CLASS(源码中有,class文件也有)
RetentionPolicy.RUNTIME(源码中有,class文件也有,运行时在内存中还有(反射注解是就必须用到这个值))元注解的举例及源码说明
自定义注解类
// 限定该注解类用在哪个位置上(value是数组的类型的,可以有多值)@Target(value={ElementType.TYPE})
// 限定该注解类的保留方式(value并不是数组类型的)@Retention(value=RetentionPolicy.RUNTIME)
// 创建注解类public @interface AnnotationDemo1 {
// String类型的注解(属性),带默认值String name() default "小强";
// 基本数据类型的注解(属性)int age();
// 数组类型的注解(属性)double[] value();
// 枚举类型的注解(属性)EnumDemo1 e();
// Class类 类型的注解(属性)Class clazz();
// 注解类型的注解(属性)MyAnno m();
}
// 枚举类(自定义注解类属性测试用)public enum EnumDemo1{
param1,param2,param3
}
// 简单注解类(自定义注解类属性测试用)public @interface MyAnno{
String value();
int num();
}
// 使用自定义的注解类@AnnotationDemo1(
age=20,
value={1.3,5.4},
e=EnumDemo1.param1,
clazz=AnnotationTest.class,
m=@MyAnno(value="value不能省略了",num=555)
)
class AnnotationTest{
}上面代码中的AnnotationDemo1注解类利用Xjad的反编译结果
反射读取注解
@AnnotationDemo1( // 该注解类在上面的代码里age=10,
value={10.8,10.9},
e=EnumDemo1.param1,
clazz=GetAnnotationTest.class,
m=@MyAnno(value="类上使用",num=100)
)
public class GetAnnotationTest {
// 类属性(字段)上使用注解@AnnotationDemo1(
age=20,
value={20.8,20.9},
e=EnumDemo1.param2,
clazz=GetAnnotationTest.class,
m=@MyAnno(value="字段上(类属性)使用",num=200)
)
private String name = "张三";
// 类方法上使用注解@AnnotationDemo1(
age=30,
value={30.8,30.9},
e=EnumDemo1.param3,
clazz=GetAnnotationTest.class,
m=@MyAnno(value="类方法上使用",num=300)
)
public void method(){
}
/** Class类,Method类,Field类,等都实现了AnnotatedElement接口* AnnotatedElement接口就是用来获取注解类对象(Annotation)的* 所有的注解类都实现了Annotation接口(类比 所有类的超类Object)* 所以,可以通过反射来获取注解类对象,再去获取其中的值*/
@Test
public void test() throws NoSuchFieldException, SecurityException, NoSuchMethodException{
// 获取Class对象Class clazz = GetAnnotationTest.class;
// 获取该Class对象上的注解对象(传递的参数就是该注解对象的Class对象)AnnotationDemo1 classAnno = clazz.getAnnotation(AnnotationDemo1.class);
output(classAnno);
// 获取Field对象Field field = clazz.getDeclaredField("name");
// 获取该Field对象上的注解对象(传递的参数就是该注解对象的Class对象)AnnotationDemo1 fieldAnno = field.getAnnotation(AnnotationDemo1.class);
output(fieldAnno);
// 获取Method对象Method method = clazz.getMethod("method");
// 获取该Method对象上的注解对象(传递的参数就是该注解对象的Class对象)AnnotationDemo1 methodAnno = method.getAnnotation(AnnotationDemo1.class);
output(methodAnno);
}
public void output(AnnotationDemo1 anno) {
System.out.println("自定义的AnnotationDemo1注解类:");
System.out.println("参数类型:int,值:age="+anno.age());
System.out.println("参数类型:double数组 ,值:value="+
Arrays.toString(anno.value()));
System.out.println("参数类型:枚举(enum)类,值: e="+anno.e());
System.out.println("参数类型:Class对象,值:clazz="+
anno.clazz().getSimpleName());
System.out.println("参数类型:Myanno注解,值: m的value值="+
anno.m().value()+",m的num值"+anno.m().num());
}
}
输出结果:
自定义的AnnotationDemo1注解类:
参数类型:int,值:age=10
参数类型:double数组 ,值:value=[10.8, 10.9]
参数类型:枚举(enum)类,值: e=param1
参数类型:Class对象,值:clazz=GetAnnotationTest
参数类型:Myanno注解,值: m的value值=类上使用,m的num值100
自定义的AnnotationDemo1注解类:
参数类型:int,值:age=20
参数类型:double数组 ,值:value=[20.8, 20.9]
参数类型:枚举(enum)类,值: e=param2
参数类型:Class对象,值:clazz=GetAnnotationTest
参数类型:Myanno注解,值: m的value值=字段上(类属性)使用,m的num值200
自定义的AnnotationDemo1注解类:
参数类型:int,值:age=30
参数类型:double数组 ,值:value=[30.8, 30.9]
参数类型:枚举(enum)类,值: e=param3
参数类型:Class对象,值:clazz=GetAnnotationTest
参数类型:Myanno注解,值: m的value值=类方法上使用,m的num值300
注解反射总结
1. 要求
* 注解的保留策略(@Retention)必须是RUNTIME
2. 反射注解需要从作用目标上返回
* 类上的注解,需要使用Class来获取
* 方法上的注解,需要Method来获取
* 构造器上的注解,需要Construcator来获取
* 成员上的,需要使用Field来获取
3.获取注解对象的方法
* Annotation getAnnotation(Class):返回目标上指定类型的注解!
* Annotation[] getAnnotations( ):返回目标上所有注解!