反射

发布于 2022-05-20  61 次阅读


概念

1反射机制允许程序在执行期借于ReflectionAPI取得任何类的内部信息,并能操作对象的属性及方法。反射在设计模式和框架底层都会用到

2.加载完类之后,在堆中就产生了一个class类型的对象(一个类只有一个class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的完整结构信息。通过这个对象得到类的结构,这个对象就像一面镜子,所以称为反射

反射的优点和缺点

1.优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑

2.缺点:使用反射基本是解释执行,对执行速度有影响

反射调用优化——关闭访问检查

1.Method和Field、Constructor对象都有setAccessible()方法

2.setAccessible作用是启动和禁用访问安全检查的开关

3.参数值为true表示 反射的对象在使用时取消检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查

calss类

1.class也是类,因此也继承Object类

2.class类对象不是new出来的,而是系统创建的

3.对于某个的Class类对象,在内存中只有一份,因为类只加载一次

4.每个类的实例都会记得自己是由哪个Class实例所生成

5.通过Class可以完整的获取到一个类的完整结构,,通过一系列API

6.Class对象是存放在堆的

7.类的字节码二进制数据,是放在方法区,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等)

Class类的常用方法:

方法名功能说明
static Class forName(String name) 返回指定类名 name 的Class 对象
Object newlnstance()返回该Class对象的实例
getName()返回此Class对象所表示的实体(类,接口,数组类,基本类型等)名称
Class getSuperClass()返回当前Class对象的父类的Class对象
Class [] getInterfaces() 获取当前Class对象接口
ClassLoader getClassLoader()返回该类的类加载器
Class getSuperclass()返回表示此Class所表示的实体的超类的Class
Constructor[] getConstructors()返回一个包含某些Constructor对象的数组
Field[] getDeclaredFields()返回Field对象的一个数组
Method getMethod(String name,Class..... paramTypes)返回一个Method对象,此对象的形参类型为param Type

以下类型要Class对象

1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类

2.interface:接口

3.数组

4.enum:枚举

5.annotation:注解

6.基本数据类型

7.void

类加载

基本说明

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载

1.静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

2.动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性

类加载时机

1.创建对象时//静态加载

2.子类被加载时,父类也加载//静态加载

3.调用类中的静态成员时//静态加载

4.通过反射//动态加载

加载阶段

jvm在该阶段的主要目的是将字节码从不同的数据源(可能是class文件,也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

连接阶段-验证

1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全

2.包括:文件格式验证(是否以魔数 oxcafebabe开头)、元数据验证、字节码验证和符号引用验证

3.可以考虑使用-Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

Initialization(初始化)

1.到初始化阶段,才真正开始执行类中定义的java程序代码,此阶段是执行<clinit>()方法的过程

2.<clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。

3.虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clint>()方法,其他线程都需要阻塞等待,直到活动线程执行<clinit>()方法完毕

通过反射获取类的结构信息

java.lang.Class类

1.getName:获取全类名

2.getSimpleName:获取所有

3.getFields:获取所有public修饰的属性6.

4.getDeclaredFilelds:获取到本类中所有属性

5.getMethods:获取所有public修饰的方法

6.getDeclaredMethods:获取本类中所有的方法

7.getConstructors:获取所有public修饰的构造器

8.getDeclaredConstructors:获取本类中所有构造器

9.getPackage:以package形式返回 包信息

10.getSuperClass:以Class形式返回父类信息

11.getInterfaces:以Class[]形式返回接口信息

12.getAnnotations:以Annotation[]形式返回注解信息

java.lang.reflect.Field类

1.getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,protected 是 4,static是8,final是 16]

2.getReturn Type:以Class形式获取 返回类型

3.getName:返回方法名

4.getParameterTypes:以Class[]返回参数类型数组

java.lang.reflect.Method类

1.getModifiers:以int形式返回修饰符

2.getReturnType:以Class形式获取 返回类型

3.getName:返回方法名

4.getParameterTypes:以Class[]返回参数类型数组

java.lang.reflect.Constructor类

1.getModifiers:以int形式返回修饰符

2.getName:返回构造器名(全类名)

3.getParameterTypes:以Class[]返回参数类型数组

通过反射创建对象

1.方式一调用类中的public修饰的无参构造器

2.方式二:调用类中的指定构造器

3.Class类相关方法

newInstance:调用类中的无参构造器,获取对应类的对象

getConstructor(Class..clazz):根据参数列表,获取对应的构造器对象

getDecalaredConstructor(Class...clazz):根据参数列表,获取对应的构造器对象

4.Constructor类相关方法

setAccessible:爆破

newInstance(Object..obj):调用构造器

访问属性

1.根据属性名获取Field对象

Field f = class对象.getDeclared(属性名);

2.暴破:f.setAccessible(true)

3.访问

f.set(o,值)

syso(f.get(o))

4.如果是静态属性,则set和get中的参数o,可以写成null

访问方法

1.根据方法名和参数列表获取Method方法对象:Method m = clazz.getDeclaredMethod(方法名,XX.class);

2.获取对象:Object o = clazz.newInstance();

3.暴破:m.setAccessible(true);

4.访问:Object returnValue = m.invoke(o,实参列表);

5.如果是静态方法,则invoke的参数o,可以写成null;