注解
一、注解概述
注解就是程序中的一种特殊标记。这些标记可以在编译、类加载、运行时被读取。程序员可以通过注解在程序中添加一些额外的补充信息。Annotation 注解就是像修饰符一样,可用于修饰类、成员变量、方法等成员,注解的信息存储在 ” name = value ” 对中。
注意:注解不影响程序的执行,无论增加、删除注解,代码都会执行。
二、基本 Annotation
java.lang 包中定义了一些基本的注解:
@Override 注解告诉编译器检查方法覆盖(重写)是否符合规则。
@Deprecate 注解表示已过时,当其他程序使用已过时的类或方法时,编译器会给出警告。
@FunctionalInterface 注解表示是函数式接口。如果接口中只有一个抽象方法可以定义为函数式接口。函数式接口是为 Lambda 表达式准备的,即可以使用 Lambda 创建函数式接口实例。
三、元注解
java.lang.annotation 包中定义一组元注解。元注解就是用来修饰注解的注解
@Retention 用于指定被修饰的 Annotation 可以保留多长时间,它包含一个RetentionPolicy 类型的 value 成员变量,可以取三个值:
- RetentionPolicy.SOURCE 表示注解只能保留在源代码中
- RetentionPolicy.CLASS 表示注解记录在字节码文件中
- RetentionPolicy.RUNTIME 表示程序运行时也可以获得注解信息
@Target 指定被修饰的 Annotation 注解可以用于修饰 哪些程序单元。
- ElementType.ANNOTATION_TYPE 注释类型声明
- ElementType.CONSTRUCTOR 构造方法声明
- ElementType.FIELD 字段声明(包括枚举常量)
- ElementType.LOCAL_VARIABLE 局部变量声明
- ElementType.METHOD 方法声明
- ElementType.PACKAGE 包声明
- ElementType.PARAMETER 参数声明
- ElementType.TYPE 类、接口(包括注释类型)或枚举声明
@Documented 表示被修饰的 Annotation 可以被 javadoc 提取成文档
四、自定义 Annotation
语法:
[修饰符] @interface 注解名 {
数据类型 属性名() default 默认值;
}
五、案例:模拟框架
package cn.powernode.javase.annotation.spring_ioc; import java.io.File; import java.io.FileInputStream; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import java.util.Properties; /* 模拟框架: 1.框架什么读取配置文件 将注解标注的类创建对象并放入容器中 应该在框架启动时,第一时间就要读取配置文件,创建实例对象,放入到容器中,供程序员取用对象 2.静态代码块(在类加载时执行,而且只会执行一次,用它进行类中内容的初始化操作) static{ 代码片段 } */ public class SpringIOCTest { static HashMap<String,Object> map = new HashMap<>(); // 容器,存储类对象 public static void main(String[] args) { // 根据指定名称获取对应的对象 Object stu = map.get("stu"); Object tea = map.get("tea"); Object work = map.get("work");
// 若成功创建实例对象,会调用 toString()方法 System.out.println(stu); //结果: null System.out.println(tea); //结果: Teacher{} System.out.println(work); //结果: Worker{} } // 静态代码块 static{ try{ // 1.读取配置文件 Properties properties = new Properties(); FileInputStream fis = new FileInputStream("day15\\applicationContext.properties"); properties.load(fis); // 2.获取配置文件中的包路径 String packagePath = properties.getProperty("packagePath"); // cn.powernode.javase.annotation.bean // 3.将包路径转换为磁盘路径 String s = packagePath.replace(".", "\\"); File file = new File("day15\\src", s); // day15\src\cn\powernode\javase\annotation\bean // 4.获取该磁盘文件夹下的文件名称 String[] list = file.list(); ArrayList<String> fileNames = new ArrayList(); // 遍历数组,拿到每一个文件名称 xx.java for (String fileName : list) { // 对于每一个文件名称 xx.java ,不要后缀 String[] split = fileName.split("\\."); // 保存每一个 去除了后缀的文件名称 fileNames.add(split[0]); } // 5.拼接 包路径+文件名称,形成所有类的全路径 ArrayList<String> referencePaths = new ArrayList<String>(); for (String fileName : fileNames) { String referencePath = packagePath + "." + fileName; // 包路径+文件名称 // 使用集合保存所有类的全路径 referencePaths.add(referencePath); } // 6.遍历集合 拿到每一个类的全路径 for (String referencePath : referencePaths) { // 7.通过Class.forName()创建该类的Class类对象,类对象中包含有注解信息 Class<?> c = Class.forName(referencePath); // 8.判断该类对象中,是否有指定的注解,eg:@Create() boolean flag = c.isAnnotationPresent(Create.class); // 9.有,则创建该类的对象放入容器中 if(flag){ // 10.获取构造方法对象 Constructor<?> constructor = c.getDeclaredConstructor(); // 11.创建实例对象 new xxx() Object o = constructor.newInstance(); // 12.获取类上的注解信息 Create annotation = c.getAnnotation(Create.class); // 13.获取注解的属性内容 String key = annotation.value(); // 14.放入容器中 map.put(key,o); // eg: stu : new Student() } } }catch (Exception e){ e.printStackTrace(); } } }