注解基本概念
注解(元数据)为我们在代码中添加信息提供一种形式化的方法,我们可以在某个时刻非常方便的使用这些数据。将的通俗一点,就是为这个方法增加的说明或功能。
作用:
- 编写文档:通过代码里标识的注解生成文档【生成doc文档】
- 代码分析:通过代码里的标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里的标识的注解让编译器实现基本的编译检查
JDK提供的注解
Java目前内置了三种注解@Override、@Deprecated、@SuppressWarnnings
@Override:用于标识方法,标识该方法属于重写父类的方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Deprecated:用于标识方法或类,标识该类或方法已过时,建议不要使用
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@SuppressWarnnings:用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告(压抑警告)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
元注解
Java提供了四种元注解,即修饰注解的注解。观察上面源码可以发现三种,即:@Target、@Retention、@Document、@Inherited。主要作用如下:
名称 | 作用 | 属性值 | 取值 |
@Target | 标识该注解用于什么地方 | ElementType | CONSTRUCTOR:构造器上声明 FILED:属性上声明 LOCAL_VARIABLE:局部变量上声明 METHOD:方法上声明 PACKAGE:包声明 TYPE:类、接口、enum上使用 |
@Retention | 表示在注解保留的阶段 | RetentionPolicy | SOURCE:注解在编译时丢掉 CLASS:注解在class文件中存在,但会被jvm丢弃 RUNTIME:jvm会保留注释,可以通过反射机制获取注解信息 |
@Document | 描述注解是否被抽取到API文档 | ||
@Inherited | 允许子类继承父类的注解 |
如何自定义注解
使用@interface定义注解,会自动继承java.lang.annotation.Annotation接口,类似于类自动继承Object一样。注解中的每个方法表示一个配置参数,返回类型即是参数类型,可以通过default标识参数默认值。
本质:就是一个接口默认继承java.lang.annotation.Annotation接口
定义方式如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)//十分重要
@Target(ElementType.METHOD)
public @interface Test {
String value() default "";
}
注解中的参数类型
注解中的参数只支持如下类型:
- 所有的基本类型:byte、short、char、int、long、float、double
- String类型
- Class类型
- enum类型
- Annotation类型
- 以上类型的数组
如果定义其他类型的参数编译器会报错。
使用注解的注意点
- 如果注解只有一个参数,最好取名value,这样在使用的时候可以直接指定属性值。例如:@Test("hello")
- 只能使用public和默认权限修饰符修饰参数
- 参数默认值:注解参数必须有确定的值。要么在定义的时候给默认值;要么在使用注解的时候指定参数值。
- 赋值时,如果只有一个属性,且属性名是value,则value可以省略,直接定义值即可。,数组赋值时,值用{ }包裹,但是数组只有一个值时,则{ }可以省略
注解处理器
如果没有读取注解的方法,那么该注解就没有任何意义。使用注解的过程中,注解处理器是必不可少的,Java反射机制,完成对注解的处理 。
注解处理器类库
Java通过反射机制获取类、方法、属性上的注解,因此java.lang.reflect提供AnnotationElement支持注解,主要方法如下:
boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该元素是否被annotationClass注解修饰
<T extends Annotation> T getAnnotation(Class<T> annotationClass):获取 该元素上annotationClass类型的注解,
如果没有返回null(// 其实就是在内存中生成一个该注释接口的子类实现对象)
Annotation[] getAnnotations():返回该元素上所有的注解
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass):返回该元素上指定类型所有的注解
Annotation[] getDeclaredAnnotations():返回直接修饰该元素的所有注解
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass):返回直接修饰该元素的所有注解
总测试源码:每个分割是一个类
@Retention(RetentionPolicy.RUNTIME) //一定要加这个注解(注解的保留阶段)
public @interface WebServlet2 {
public String value() default "";
public String url() default "";
public String name() default "";
}
/***************/
@WebServlet2(url = "/load3",name = "无语")
public class demo3 {
void show(){
System.out.println("我是demo3");
}
}
/***************/
@WebServlet2(url = "/load")
public class demo2 {
void show(){
System.out.println("我是demo2");
}
}
/***************/
@WebServlet2(url = "/load")
public class demo1 {
void show(){
System.out.println("我是demo1");
}
}
/***************/
package com.aqiuo.反射;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class SumDemo {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String arr[] =new String[]{"com.aqiuo.反射.demo1","com.aqiuo.反射.demo2","com.aqiuo.反射.demo3","com.aqiuo.反射.Person"};
String urlname="/load";
Class[] cls=new Class[arr.length];
for (int i=0;i<arr.length;i++) {
cls[i]=Class.forName(arr[i]);
WebServlet2 annotation= (WebServlet2) cls[i].getDeclaredAnnotation(WebServlet2.class);
if(annotation!=null) {
String url = annotation.url();
if (url.equals(urlname)) {
System.out.println(arr[i]);
Object x = cls[i].newInstance();
Method method = cls[i].getDeclaredMethod("show");
method.invoke(x);
}
}
}
}
}
小结:
- 以后大多数时候,我们会使用注解,而不是自定义注解
- 注解给谁看:
- 编译器
- 解析程序
- 注解不是程序的一部分