反射机制

反射机制

个人理解:

在运行代码/编译代码时,在此期间通过调用(.class)方式,得到你想要的类,任意构造器,方法,属性等,特别的,私有的方法也可以被得到。

不使用反射的类,就要考虑类的封装性,例如person类,就不可以调用person里面私有的类

在实际开发中,很少使用反射。

在设计框架的时候就经常使用反射,所以在学习框架源码时,就需要学习反射,体现了反射的动态性;

框架 = 注解 + 反射 + 设计模式

封装性:体现的是建议我们是否调用里面的方法,如果是建议的话,就是用public,不建议就使用private

反射:类是全部完整的存在内存中,所以我们就有能去调用里面的所有方法

以下图就是反射例子,好比一个镜子:

 

 

反射最重要的用途就是开发各种通用框架。

 

反射的应用:

1、创建运行时类的对象:通过Class的实例调用newInstance()方法即可;

Class<?> c = String.class;

Object str = c.newInstance();

注意:创建对象成功,需要满足:

  • 要求运行时类中必须提供一个空参的构造函数

  • 要求提供的空参构造函数的权限要足够

2、JavaBean中要求给当前类提供一个公共的空参的构造函数,有什么用?

  • 子类对象在实例化时,子类的构造器的首行是先调用父类的构造器

  • 在反射中,经常用来创建运行时的对象。所以我们在编写代码时,要在pojo包下的类写一个空参构造器,便于我们创建运行代码时类的对象。

3、调用指定的属性,方法,构造函数

public class test01 {
    /*
    调用运行时的属性:
    主要是这几个方法,在此不再赘述:
    getFiled:访问公有的成员变量
    getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量
    getFileds 和 getDeclaredFields 方法用法同上(参照 Method)。
     */
    @Test
    public void test1() throws Exception {
        //在运行时创建类对象
        Class clazz = Person.class;
        Person per = (Person) clazz.newInstance();
        //getDeclaredField 获得运行时的某一属性
        Field field = clazz.getDeclaredField("name");
​
        //确保此属性是可以访问的
        field.setAccessible(true);
​
        //set/get 设置和获取操作
        field.set(per,"ljx");
        System.out.println(field.get(per));
    }
    /*
    调用运行时的方法:
    获取某个Class对象的方法集合,主要有以下几个方法:
    getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包    括继承的方法。
    public Method[] getDeclaredMethods() throws SecurityException
    getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
    public Method[] getMethods() throws SecurityException
    getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。
    public Method getMethod(String name, Class<?>... parameterTypes)
    */
    @Test
    public void test2() throws Exception {
        Class clazz = Person.class;
        Person per = (Person) clazz.newInstance();
        //通过getDeclaredMethod指定是方法
        Method method = clazz.getDeclaredMethod("Method", int.class);
        //确保此方法是可以访问的
        method.setAccessible(true);
​
        //通过invoke设置类方法中的值
        Object invoke = method.invoke(per, 15);
        System.out.println(invoke);
    }
    /*
    调用运行时的构造函数:
    获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor     类的一个实例,
    而Constructor类有一个newInstance方法可以创建一个对象实例:
    public T newInstance(Object ... initargs)
    此方法可以根据传入的参数来调用对应的Constructor创建对象实例。
     */
    @Test
    public void test3() throws Exception {
        Class clazz = Person.class;
        //通过getDeclaredConstructor获得构造函数的参数类型
        Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
        //确保此构造函数是可以访问的
        constructor.setAccessible(true);
        //通过newInstance获得构造函数的参数
        Person person = (Person) constructor.newInstance("ljx", 15);
        System.out.println(person);
    }
}

 

问题:

  • 对反射有了解吗?反射有什么好处?为什么需要反射?

  • 反射是如何实现的?

    从class说起。

  • class类的作用?生成class对象的方法有哪些?

    反射的源头。

    方法有三种:

    (1) 使用 Class 类的 forName 静态方法:

     public static Class<?> forName(String className)
    ```

    比如在 JDBC 开发中常用此方法加载数据库驱动:

    ```java
    Class.forName(driver);

    (2)直接获取某一个对象的 class,比如:

    Class<?> klass = int.class;
    Class<?> classInt = Integer.TYPE;

    (3)调用某个对象的 getClass() 方法,比如:

    StringBuilder str = new StringBuilder("123");
    Class<?> klass = str.getClass();
  • Class.forName("全路径")会调用哪些方法?会调用构造函数吗?加载类会放在哪里?

    Class.forName()会执行执行类构造器<clinit>()方法。

    不会调用构造函数。

    加载的类放在方法区。

  • 如何找到对象的实际类?

    对象.getclass( )

    Object date = new Date();
    date.getClass();
    //获取到的是Date
  •  
posted @ 2023-03-09 17:05  jessi呀  阅读(15)  评论(0编辑  收藏  举报