反射 + 获取类的Class对象的几种方式 + 触发类的加载几种情况

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

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值