JAVA Reflection
概述
- Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期间,借助反射的API获取任何类的内部信息,并且直接操作任意对象的内部属性及方法。
-
Class c =Class.forName("java.lang.String")
- 加载完类之后,在堆内存的方法区就产生了一个Class类型的对象(一个类只有一个class对象),这个对象包含了本类的完整的类的结构信息(==构造器、方法、属性 - 反射方式:实例化对象---->getClass()方法(属于Object类)---->得到完整的“包类”名称
- 正常方式:引入需要的“包类”名称---->通过new实例化---->取得实例化对象
- 一些应用场景:在运行时判断任意一个对象所属的类、在运行时处理注解、在运行时构造任意一个类所具有的成员变量和方法、在运行时获取泛型信息、生成动态代理…
优缺点
- 优点:可以动态的创建对象和编译,体现出很大的灵活性
- 缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM。我们希望做什么并且满足我们的要求。这类操作总是慢于直接执行相同的操作(如new)
Class类
概述:
1、Class类本身也是一个类
2、Class只能由系统建立对象
3、一个加载的类在JVM中只会有一个实例
4、一个Class对象对应的是一个加载到JVM中的一个.class实例
5、每个类的实例都会记得自己是由哪个Class实例所生成
6、Class类存有一整个类中的所有结构
7、Class类是Reflection的根源,针对任何你想加载动态加载、运行的类、唯有先获得相应的
Class对象
- 在Object类中定义了一下方法,此方法将被所有子类继承
public final Class getClass()
- 以上方法的返回类型是一个Class类,实际上所谓反射从程序的运行结果来看也很好理解,即,可以通过对象反射求出类的名称。
- 创建class类的四种方式:
1、通过已知的具体类的class属性获得(最安全可靠,程序性能最高)
Class c = Studengt.class;
2、已知类的一个对象,调用该实例的getClass()方法获得Class对象
Class c1 = student.getclass;
3、已知一个类的全类名,通过Class类的静态方法forName()获取,需要抛出ClassNotFonudException
Class c2 = Class.forName("com.demo1.Student");
4、基本内置类型(如String、Integer等)可以用类名.TYPE
Class c3 = Integer.TYPE;
- 所有类型的Class:c
1、class:外部类、成员(成员内部类、静态内部类),局部内部类,匿名内部类
2、interface:接口
3、[]:数组
4、enum:枚举
5、annottion:注解
6、primitive type:基本数据类型
7、void
Class c1 = Object.class;
Class c2 = Comparable.class;//接口
Class c3 = String[].class;//一维数组:
//数组:元素与维度一样,就是同一个class对象,即hashCode相同
Class c4 = int[][].class;//二维数组
Class c5 = Override.class;
Class c6 = ElementType.class;//枚举
Class c7 = Integer.class;
Class c8 =void.class;
Class c9 = Class.class;
类的加载与ClassLoader(类加载器)
类加载:把类装载进内存
- 加载:将class字节码文件加载到内存中,并且将这些静态数据装换成方法区的运行时数据结构,然后生成一个class对象(java.lang.Class)
- 链接:将Java类的二进制代码合并到JVM的运行状态中
1、验证:确保加载的类信息符合JVM规范,没有安全问题
2、准备:正式为类变量(static)分配内存(方法区)并设置类变量的默认初始值阶段
3、解析:虚拟机常量池内的符号引用替换成直接引用的过程 - 初始化:
1、执行类构造器方法的过程。类构造器()方法是由编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生;
2、初始化一个类时时,父类优先。
一些要掌握的方法
创建运行时类的对象
首先需要获取Class对象:调用Class对象的newInstance()方法
1、类必须有无参构造器
2、类的构造器访问权限需要足够
类没有无参构造器的情况:
1)通过Class类的getDeclaredConstructor函数取得本类的指定形参类型的构造器
2)向构造器的形参中传的一个对象数组进去,里面包含了构造器中所需的各个参数
3)通过constructor实例化对象
获取类运行时的完整结构
通过反射获取运行时类的完整结构
Fiedl、Method、Construcutor、Superclass、Interface、Annotation
- get开头的方法:只能获取public的属性
- getDeclared开头的方法:能获取全部属
通过反射调用制定方法: (object invoke(Object obj,Object …args))
- 通过Class类中的getMethod(String name ,Class…parameterTypes)方法获得一个Method对象,并设置此方法操作室和所需要的对象
- 在调用Object invoke(Object obj,Object[] args)进行调用,并在方法中传递要设置的obj对象的参数信息,通过invoke调用CLass中的方法,并且传递参数
- object invoke(Object obj,Object …args)要点:
1、Object对应原方法的返回值,无返回值则为null
2、若原方法为静态方法,则形参Object obj为null
3、若原方法形参列表为空,则Object[] args为null
4、若原方法声明为private,则要钓友方法对象的setAccessible(true)方法
setAccessible: