1注解
1.1概述
注释:// // / */
<%– –%>给开发人员看的。
注解:给机器(编译器、类加载器、JVM)看的
使用注解的格式: @注解名称(属性名1=属性值1,…,属性名n=属性值n)
作用:在一些开发的场景中实现轻量级的配置。
副作用是:增加了耦合度
注意:JDK API文档中将注解误译成了注释。
1.2常见的注解
1.2.1 @Override表示重写父类的方法
在编译时验证以下几点信息:修饰符范围>=父类的方法;方法的签名和返回值也得一样。
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
1.2.3 @SuppressWarnings:抑制编译器显示警告信息的
比如:@SuppressWarnings(“unused”)抑制编译器显示未被使用的警告信息
1.3自定注解的开发流程:
定义注解(创建一个注解类)->反射注解->使用注解
1.4 定义注解
1.4.1自定义注解的基本格式:
public @interface 注解名称 {}
比如:public @interface Anno1 {}
底层帮我们自动实现java.lang.annotation.Annotation接口
1.4.2源生注解:用于修饰注解的注解。
@Target(ElementType.XXX):表示被修饰的注解能够在什么元素(类和接口,方法、属性、成员变量、构造方法..)上使用
@Retention(RetentionPolicy.SOURCE):表示注解的保留域。
@Documented:表示生成的javadoc中是否保留注解的信息。
1.4.3注解中的属性
1、注解属性的定义和接口中方法的定义类似,默认是public,所以public可以省略。public String name();
2、属性定义可以通过default为属性指定默认值,指定默认值的属性,在注解使用时,可以为之赋值,也可以不为之赋值。如果不通过default为属性指定默认值,在注解使用必须使用该属性并且还得为之赋值。
3、如果在一个注解中,某个属性必须使用并且需要给他赋值注解才能被使用,可以在属性定义时不使用default指定默认值。
4、注解中有一个特殊的属性value,如果仅为该属性赋值,”value=”可以省略掉,但是如何和其他属性同时赋值,“value=”则不能省略。和该属性的类型无关,仅和名称有关。
5、属性的类型可以八种基本数据类型、Class、枚举、String等,以及以上类型的一维数组。
6、如果属性是一维数组,在赋值值如果仅有一个值“{}”才可以省略。
1.4.4.1@Target(ElementType.XXX):
表示被修饰的注解能够在什么元素(类和接口,方法、属性、成员变量、构造方法..)上使用
***CONSTRUCTOR构造方法声明
FIELD 字段声明(包括枚举常量)
LOCAL_VARIABLE 局部变量声明
METHOD方法声明
PACKAGE包声明
PARAMETER参数声明
TYPE类、接口(包括注解类型)或枚举声明*
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
} //表示该注解只能被用在方法上。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
} //Retention注解只能被用在注解上。
1.4.4.2
@Retention(RetentionPolicy.SOURCE)
表示注解的保留域。
*补充:
编译器 类加载 JVM
.java –>.class –>被加载到内存中->运行*
RetentionPolicy.SOURCE:给编译器看,编译器编译后该类型的注解就被丢弃掉了。(生成.class字节码文件中,将不再存在该类型的注解)
RetentionPolicy.CLASS:字节码级别的,给类加载器看的,在类被加载时做一些引导相关的一些操作。编译器编译保留,类加载器加载时使用,加载后丢弃掉。
RetentionPolicy.RUNTIME:给JVM看的,编译器编译后保留,类加载器加载保留,在运行时,JVM使用。
通常自定义的注解都是使用该保留域,在程序运行时反射注解中的信息,并根据属性的值做相关的操作。
1.4.4.3@Documented:
表示生成的javadoc中是否保留注解的信息。如何使用注解
1.4.5如何反射注解
@Retention(RetentionPolicy.RUNTIME)
如果注解想要被反射,注解的保留域必须设置为RUNTIME保留域。
jdk中提供的注解反射接口:AnnotatedElement,提供了以下几个方法:
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这个注解,否则返回 null
Annotation[] getAnnotations()
返回此元素上存在的所有注解。
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
已知该接口的实现类:Class, Constructor,Field, Method, Package 以上这些类的对象均可调用反射的相关方法。
案例如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PoliceLevel {
public String level() default "";
}
@PoliceLevel(level="大队长")
public class Police {
public void getMoney(){
System.out.println("敬个礼,您违章了,罚款200....");
}
public static void main(String[] args) {
/*Police pc = new Police();
pc.getMoney();*/
Polic pc = new Polic();
pc.getMoney();
//判断真假
if(pc.getClass().isAnnotationPresent(PoliceLevel.class)){
//真交警
PoliceLevel pl = pc.getClass().getAnnotation(
PoliceLevel.class);
//获取注解中属性的值
String level = pl.level();
if("协警".equals(level)){
System.out.println("哥们抽个烟,偷么给50,不需要开票");
}else if("交警".equals(level)){
System.out.println("给200元...");
}else if("大队长".equals(level)){
System.out.println("给2000,麻烦给开一个免罚牌");
}
}else{
System.out.println("抽一顿,送到警察局...");
}
}
}