1、反射的定义
在java运行状态中,通过Class对象获取类对象的成员结构,并可以对其成员动态取值、赋值操作,这样的机制就是反射。
那么Class对象怎么知道每个类的信息呢 ? 可以通过一张图来窥其一二:
注:笔者第一次看官方定义,感觉不是那么好理解,无意中找到了一张以前保存的图片(侵删)
上图介绍了一个java类文件从编译成 .class 文件 到程序运行加载到JVM后,JVM会自动创建一个它的 专属 Class类,里面封装了该类的基本信息(类名,所在包名,类的属性,方法。。。),所以自然就有了获取该类信息的前提。
2、获取Class对象和反射的基本使用
- java中提供了四种方式获取Class对象,Class.forName()性能较差,底层会进行安全验证和访问本地native方法(操作系统),《Java编程思想》中比较推荐的方式是 类名.class
- 可以通过Class对象获取类信息、操作属性、方法、构造函数等,注意访问静态成员、访问private成员时的写法。
示例代码:
package se.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyReflect {
private String s1;
public String s2;
public static String s3;
public void setS1(String s1) {
this.s1 = s1;
}
public String getS1() {
return s1;
}
public String getS2() {
return s2;
}
public void setS2(String s2) {
this.s2 = s2;
}
public static String getS3() {
return s3;
}
public static void setS3(String s3) {
MyReflect.s3 = s3;
}
private void m01(String s){
System.out.println(s);
}
public void m02(String ss){
System.out.println(ss);
}
public static void staticMethod(String str){
System.out.println(str);
}
}
class TestMyReflect{
public static void main(String[] args) throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//+++++++++++++++++++++ 反射的获取方式++++++++++++++++++++++++
//1、通过 ClassLoader 的 loadClass() 方法
ClassLoader cl = ClassLoader.getSystemClassLoader();
Class<?> aClass = cl.loadClass("se.reflect.MyReflect");
//2、通过类名.class
Class<MyReflect> myReflectClass = MyReflect.class;
//3、 通过Class.forName()
Class<?> aClass1 = Class.forName("se.reflect.MyReflect");
//4、 通过对象.getClass()
MyReflect myReflect = new MyReflect();
Class<? extends MyReflect> aClass2 = myReflect.getClass();
//+++++++++++++++++++++ 反射基本使用++++++++++++++++++++++++
// 1、 类信息获取 示例
System.out.println(aClass2.getClassLoader()); //获取类加载器名字
System.out.println(aClass2.getAnnotations()); //获取类注解
System.out.println(aClass2.getPackage()); //获取类包名
System.out.println(aClass2.getModifiers()); //获取类修饰符
// 2、 类属性操作
MyReflect myReflect1 = aClass2.newInstance();
Field s1 = aClass2.getDeclaredField("s1");
s1.setAccessible(true); //private 属性需要设置强制访问
s1.set(myReflect1,"我是s1的值");
System.out.println(myReflect1.getS1());
Field s3= aClass2.getDeclaredField("s3");
s3.set(null,"我是静态属性"); //调用静态属性,属于类级别,不能传对象
System.out.println(myReflect1.s3);
//3、 类方法操作
Method m01 = aClass2.getDeclaredMethod("m01", String.class);
m01.setAccessible(true); //private 方法需要设置强制访问
m01.invoke(myReflect1,"调用了m01()方法");
Method staticMethod = aClass2.getDeclaredMethod("staticMethod", String.class);
staticMethod.invoke(null,"调用了静态方法"); //调用静态方法,属于类级别,不能传对象
}
}
输出:
3、反射的优缺点
优点 : 增加程序灵活性,复用率
缺点:创建较多对象时,性能较差(找.class文件时需要频繁验证)
使类的内部暴露,存在安全隐患
4、反射的应用
- springIOC
具体可以暂时参考 :https://www.cnblogs.com/esileme/p/7479879.html ,很简明。 - JDBC 加载驱动类 Class.forName() 进行加载驱动等初始化操作。
static{
try {
Class.forName("com.mysql.jdbc.Driver");//加载数据库驱动
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}