注解的使用
-
概念
- 注解(Annotation),也叫元数据。一种代码级别的说明,与类、接口、枚举在同一个层次,它可以声明在包、类、字段、方法、局部变量、方法参数等方面,用来对这些元素进行说明、注释。
- 概念描述:
- JDK1.5之后的新特性
- 说明程序的
- 使用注解:@注解名称
- 作用分类:
- 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】 javadoc命令生成doc文档
- 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
- 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【override】
-
JDK内置注解
- @override :检测被该注解标注的方法是否是继承自父类或者父接口
- @Deprecated:将该注解标注的内容,表示已过时
- @SuppressWarnings:压制警告,可以传参数,一般是all
-
自定义注解
- 格式:
- 元注解
- public @interface注解名称{属性列表;}
- 本质
- 注解本质上是一个接口,该接口默认继承Annotation接口
- 格式:
-
属性定义
- 属性:接口中的抽象方法
- 要求:
- 属性的返回值类型
- 基本数据类型
- 字符串
- 枚举
- 定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时可以不进行属性的赋值
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
- 数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}可以省略
- 属性的返回值类型
- 要求:
- 属性:接口中的抽象方法
-
元注解
- 定义:用于描述注解的注解
- @Target:描述注解能够作用的位置
- ElementType 取值:
- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
- @Retention:描述注解被保留的阶段
- @Retention(RetentionPolicy.SOURCE)
- @Retention(RetentionPolicy.RUNTIME):一般自定义注解都是runtime,当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
- @Retention(RetentionPolicy.CLASS)
- @Documented:描述注解是否被抽取到api文档中
- @Inherited:描述注解是否被子类继承
-
解析注解
- 在程序使用(解析)注解:获取注解中定义的属性值
- 获取注解定义位置的对象
- 获取指定的注解 getAnnotation(Class)
- 调用注解中的抽象方法获取配置的属性值
-
-
案例
- 实现手写httpServlet中的WebServlet的注解开发
- @WebServlet
package com.wbyq.httpserver.annotation; import java.lang.annotation.*; /** * 用来描述servlet和url映射关系 * @author AlmostLover */ @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebServlet { String name() default ""; String value() default ""; String[] urlPatterns() default {}; String description() default ""; }
2.WebServletImpl.java
package com.wbyq.httpserver.annotation.impl; import com.wbyq.httpserver.annotation.WebServlet; import java.io.File; import java.util.*; /** * servlet注解映射 * * @author AlmostLover */ public class WebServletImpl { /** * 获取有该注解的类的name值,并将其加入一个map中 */ public static Map<String, String> getServlet() { Map<String, String> map = new HashMap<>(); //获取所有拥有该注解的类 Set<Class<?>> classes = getServletClasses(); for (Class cla : classes) { //获取该注解类的Value值 WebServlet servlet = (WebServlet) cla.getAnnotation(WebServlet.class); //将该类注解的属性加入Map map.put(servlet.value(), cla.getName()); } return map; } /** * 获取指定目录文件下的java类名 * * @param filePath 文件路径 * @param className 包含类名的list集合 * @param childPackage 是否遍历子包 * @return List */ private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) { List<String> myClassName = new ArrayList<String>(); File file = new File(filePath); File[] childFiles = file.listFiles(); for (File childFile : childFiles) { if (childFile.isDirectory()) { //如果有子包,并且为true则继续遍历,实现递归 if (childPackage) { myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage)); } } else { String childFilePath = childFile.getPath(); //获取后缀名为.java的文件名并加入list集合 if (childFilePath.endsWith(".java")) { childFilePath = childFilePath.substring(childFilePath .indexOf("\\", 2)).replace("\\", "."); childFilePath = childFilePath.substring(1, childFilePath.length() - 5); myClassName.add(childFilePath); } } } return myClassName; } /** * 获取有该注解的类 * * @return Set */ private static Set<Class<?>> getServletClasses() { List<String> classNames = new ArrayList<>(); //获取项目中所有的java类名 classNames = getClassNameByFile("./", classNames, true); Set<Class<?>> servletClasses = new HashSet<>(); for (String className : classNames) { try { //通过反射加载对应名称的类 Class<?> cla = Class.forName(className); //如果该类拥有@WebServlet注解则加入list集合 if (cla.isAnnotationPresent(WebServlet.class)) { servletClasses.add(cla); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } return servletClasses; } }
- @WebServlet
- 实现手写httpServlet中的WebServlet的注解开发
-
总结
- 注解给谁用
- 编译器
- 给解析程序用
- 注解不是程序的一部分,可以理解为注解就是一个标签
- 注解给谁用