refer:
文章目录
1、什么是反射
- 反射就是 在程序运行过程中,能够 动态 获取 类中的信息的机制叫做 “ 反射机制 ”。
- 对于任意一个类,都能够知道这个类的所有属性 和 方法,然后可以对这个类进行操作。
- 反射就是把java类中的各种成分映射成一个个的Java对象。
反射机制使用的前提条件:必须先得到类对应的Class,Class类用于表示.class文件(字节码)
反射机制优缺点:
优点: 动态加载类;提高代码灵活度;运行期才会进行 类型的判断(具体使用的是那种驱动,等到执行的时候才去确定,提高灵活性)。
·
缺点: 1,性能瓶颈:反射相当于 一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。2,安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。
2、获取Class对象的3种方式
当我们想要使用反射 动态的获取 类中的信息时,我们需要依靠 Class 对象。
Class对象的由来是:将 .class文件
读入内存,并为之创建一个Class对象。
- 1、
Class.forName("全类名")
:例如:加载mysql驱动。默认会执行类的初始化操作。Class.forName(className)方法
,内部实际调用的是一个native方法 forName0(className, true, ClassLoader.getClassLoader(caller), caller);- 第2个boolean参数为true表示类是否需要初始化。一旦初始化,就会触发目标对象的 static块代码执行,static参数也会被再次初始化。
- 2、通过调用 类名.class属性:通过类名的
class
属性,来获取类信息 - 3、通过对象的方法
getClass()
获取:getClass()
方法位于Object 类中。 - 4、通过类加载器
xxxClassLoader.loadClass()
传入类路径获取Class对象:- 例如:`class clazz = ClassLoader.LoadClass(“cn.javaguide.TargetObject”);
- 通过类加载器获取Class对象不会进行初始化,意味着不进行包括初始化等一些列步骤,静态块和静态对象不会得到执行
【注意】:只有通过Class.forName(“全类名”);这种方式加载类,才会执行类的初始化过程。
3、获取到类对应的Class对象后,就可以操作这个类中的方法 和 属性
1.创建一个我们要使用反射操作的类 TargetObject:
package cn.javaguide;
public class TargetObject {
private String value;
public TargetObject() {
value = "JavaGuide";
}
public void publicMethod(String s) {
System.out.println("I love " + s);
}
private void privateMethod() {
System.out.println("value is " + value);
}
}
2.使用反射操作这个类的方法以及参数
package cn.javaguide;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
/**
* 获取TargetObject类的Class对象并且创建TargetObject类实例
*/
Class<?> tagetClass = Class.forName("cn.javaguide.TargetObject");
TargetObject targetObject = (TargetObject) tagetClass.newInstance();
/**
* 获取所有类中所有定义的方法
*/
Method[] methods = tagetClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
/**
* 获取指定方法并调用
*/
Method publicMethod = tagetClass.getDeclaredMethod("publicMethod",
String.class);
publicMethod.invoke(targetObject, "JavaGuide");
/**
* 获取指定参数并对参数进行修改
*/
Field field = tagetClass.getDeclaredField("value");
//为了对类中的参数进行修改我们取消安全检查
field.setAccessible(true);
field.set(targetObject, "JavaGuide");
/**
* 调用 private 方法
*/
Method privateMethod = tagetClass.getDeclaredMethod("privateMethod");
//为了调用private方法我们取消安全检查
privateMethod.setAccessible(true);
privateMethod.invoke(targetObject);
}
}
4、类加载过程(或 Class对象的由来)?
5、哪些情况会触发 类的加载过程?
参照:https://blog.csdn.net/csdnsevenn/article/details/102597309
- 1、Class.forName(“全类名”)
- 2、new 对象();创建对象时候
- 3、使用类名 调用static成员 的时候。
完成情况如图:
6、静态编译和动态编译
静态编译: 在编译时确定类型,绑定对象(例如:使用我们自定义的类。)
动态编译: 运行时确定类型,绑定对象(例如:动态加载mysql的驱动类 com.mysql.jdbc,Driver
)