1、反射的定义
在java运行状态中,通过Class对象获取类对象的成员结构,并可以对其成员动态取值、赋值操作,这样的机制就是反射。
那么Class对象怎么知道每个类的信息呢 ? 可以通过一张图来窥其一二:

clipboard.png
注:笔者第一次看官方定义,感觉不是那么好理解,无意中找到了一张以前保存的图片(侵删)
上图介绍了一个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,"调用了静态方法"); //调用静态方法,属于类级别,不能传对象
    }
}
输出:

image.png
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();
        }
}