反射
理论
在面向对象的编程语言如Java中,反射允许在编译期间不知道接口的名称,字段(fields,即成员变量)、方法的情况下在运行时检查类、接口、字段和方法。它还允许根据判断结果进行实例化新对象和不同方法的调用。
反射还可以使给定的程序动态地适应不同的运行情况。例如,考虑一个应用程序,它使用2个不同的类X和Y互相交替执行类似的操作。没有使用面向反射编程技术,应用程序可能是硬编码的(即把代码写死,缺乏灵活性),以调用方法名称的类X和Y类。然而,使用面向反射的编程范式中,应用程序可以在设计和编写利用反射在没有硬编码方法名称情况下调用类中的方法X和Y。
Java 中,无论生成某个类的多少个对象,这些对象都会对应于同一个 Class 对象。
- Class类:反射的核心类,可以获取类的属性,方法等信息。
- Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
- Method类: Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
- Constructor类: Java.lang.reflec包中的类,表示类的构造方法。
用处
可以动态的运行指定的类和方法而不用重新编译
获取对象和方法
被反射的类
反射操作
|
|
输出结果
生成对象、执行方法、修改成员变量
生成对象
|
|
执行方法(需要先生成对象)
|
|
被执行的方法
Preson.java
修改成员变量(需要先生成对象)
|
|
类加载器
类的加载 连接 初始化
加载:
查找并加载类的二进制数据
连接:
验证:确保被加载的类的正确性
准备:为类的静态变量分配内存,并将其初始化为默认值
解析:把类中的符号引用转换为直接引用
初始化:
为类的静态变量赋予正确的初始值
类加载器
Java自带的加载器
根类加载器(使用 C++编写,程序员无法在 Java 代码中获得该类)
扩展加载器,使用 Java 代码实现
系统加载器(应用加载器),使用 Java 代码实现
用户自定义的类加载器都是 java.lang.ClassLoader 的子类
类的初始化条件
1.创建类的实例
2.访问某个类或接口的静态变量,或者对该静态 变量赋值
3.调用类的静态方法
4.反射(如 Class.forName(“com.shengsiyuan.Test”) )
5.初始化一个类的子类
6.Java虚拟机启动时被标明为启动类的类(Java Test)
注意:
1.只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以 认为是对类或接口的主动使用
2.调用ClassLoader类的loadClass方法加载 一个类,并不是对类的主动使用,不会导致类的初始化
3.如果是编译时就知道的常量类不会初始化
如果是在运行时才知道的常量类会被初始化
通过类加载器获取文件
文件路径
输出
注解
理论
Java注解,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。
Java注解可以通过反射获取标注内容。
在编译器生成类文件时,注解可以被嵌入到字节码中。
Java虚拟机可以保留注解内容,在运行时可以获取到标注内容。
当然它也支持自定义Java注解
作用在代码的注解
@Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在注解的注解(元注解)
Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
@Documented - 标记这些注解是否包含在用户文档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
Java 7 开始才有的注解
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。 @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
自定义注解
Retention
例子
其中RetentionPolicy有三种级别
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃。
RUNTIME:VM将在运行期间也保留注解,因此可以通过反射机制读取注解的信息。
Target
Target可以限定运用的场景。
例子
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
Inherited
假如父类用了@Inherited注解 那么子类也会注解父类所用的注解
例子
自定义
定义的注解
定义一个类使用注解
通过反射获取
|
|
运行结果
枚举
使用
定义枚举
使用
|
|
输出结果