java 反射 - 从入门到放弃

本贴最后更新于 1128 天前,其中的信息可能已经事过景迁

1、什么是反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
举个例子:
创建java对象时,一般是要知道类名,比如创建Student对象。
Student s = new Student();
但是有些时候,当前时间不知道类名,我又想能创建这个类的对象,这时候就不需要用到反射。
只需要拿到字节码对象,我们就能通过反射获取对象、调用方法、访问变量。
从而脱离必须在java文件中把类名写死,java赋予的这种能力,广泛运用在各大流行框架中。

2、反射的应用场景

1. 封装对象(比如把excel中一行数据封装到一个自定义对象中)
2. 工具类(比如testng、fastjson)
3. Spring框架

3、反射优缺点

优点:反射提高了程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,避免将程序写死到代码里。
缺点:通过反射创建对象比直接写代码创建对象会慢一些,因为使用反射时进行一系列的安全性校验,加载字节码也会比较慢。

4、类加载过程

上面介绍了反射的优缺点,那为什么反射会比较慢呢?这就要说到类加载过程。
类加载机制:
加载--->链接(验证、准备、解析)--->初始化--->使用--->卸载
1. 加载:字节码.class文件加载到内存中
2. 链接:
	1、验证字节码是否被篡改
	2、准备分配对应的空间
	3、解析字节码对应类的字段、父类、接口等
3. 初始化:相当于 new Student(); 创建类的对象
4. 使用:对象调用对象方法、字段等
5. 卸载:对象被回收

5、反射常用API

1、获取字节码对象

//Class.forName()
Class clazz1 = Class.forName("com.lemon.Lemon");
//类名.class
Class clazz2 = Lemon.class;
//getClass()
Lemon l = new Lemon();
Class clazz3 = l.getClass();
//通过三种方式获取的字节码对象都是相同,使用两两相等的方式比较。
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);

2、创建对象

//有两种方式可以创建对象,一用字节码调用newInstance(),二是先获取Constructor对象,在调用newInstance()
Object o1 = clazz1.newInstance();
//获取Constructor
//获取指定构造方法
Constructor constructor = clazz1.getConstructor(构造方法参数类型);
//获取所有构造方法
Constructor[] constructors = clazz1.getConstructors();
//执行构造方法
Object o2 = constructor.newInstance(参数);

3、获取属性和方法

//获取字段
Field field = clazz1.getField(字段名称);
Field[] fields = clazz1.getFields();
//设置字段
field.set(对象,字段值);
//获取字段
Object value = filed.get(对象);
//获取方法
Method method = clazz1.getMethod(方法名,方法参数类型);
Method[] methods = clazz1.getMethods();
//执行方法
Object result = method.invoke(对象,方法参数):

4、暴力反射

//被private修饰的方法和字段只能在本类访问,但是通过反射可以强行获取,这在一定程度上破坏了封装性
//上面获取构造方法、字段、方法还有一组加了Declared修饰的方法,用它就能来访问所有内容(public、protected、默认、private)
//Constructor
getDeclaredConstructors();
getDeclaredConstructor(构造方法参数类型);
//Field
getDeclaredFields();
getDeclaredField(字段名称);
//Method
getDeclaredMethods();
getDeclaredMethod(方法名,方法参数类型);
//当你获取到非公有内容还不能直接使用,还需要调用setAccessible(true)设置访问权限
constructor.setAccessible(true);
field.setAccessible(true);
method.setAccessible(true);
//好了,这样就能用尽情的使用java类中所有成员了,哦也~
回帖
请输入回帖内容 ...