1. Java反射机制概述

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期间借助于 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性和方法
加载完类之后,在堆内存的方法区中就产生了一个Class类的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子可以看到类的内部结构,因此,我们形象的称之为:反射.
image.png
注意,Java不是动态语言,它和C++一样是静态语言。但是Java有一定的动态性,被称为“准静态语言”。我们可以利用反射机制、字节码操作来获得类似动态语言的特性。

【反射机制提供的一些功能】

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

    2. 反射的强大

    一个类的外部不可以调用该类的私有结构,但是反射可以!反射可以随意调用一个类的私有构造器、私有属性、私有方法。
    Person类: ```java package pkg15;

public class Person { // 私有属性 private String name; // 私有方法 private String getName(){ return name ; } // 私有构造器 private Person(String name) { this.name = name; }

  1. @Override
  2. public String toString() {
  3. return "Person{" +
  4. "name='" + name + '\'' +
  5. '}';
  6. }

}

通过反射调用Person的私有结构:
```java
package pkg15;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception {
        Class cla = Person.class;  // 创建Class类的实例

        // 调用私有构造器
        Constructor constructor = cla.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        Object p = constructor.newInstance("zhangsan");
        System.out.println(p.toString());

        // 调用私有属性
        Field name = cla.getDeclaredField("name") ;  // 传入属性名
        name.setAccessible(true);
        System.out.println(name);
        name.set(p,"lisi");
        System.out.println(p);

        // 调用私有方法
        Method getName = cla.getDeclaredMethod("getName");// 传入方法名和入参类型
        getName.setAccessible(true);
        Object invoke = getName.invoke(p);// invoke 指调用,p指定调用方法的对象
        System.out.println(invoke);
    }
}

image.png
反射调用私有方法可以来感受一下,原来正常是对象调用方法,现在变成了方法调用对象。

3. Class类的理解

  • 类的加载过程:
    • 程序经过编译(javac)命令以后,会生成一个或多个字节码文件,接着我们使用运行(java)命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中,此过程就成为加载。加载到内存中的类就成为了运行时类,此运行类就作为Class的一个实例。可以理解为:类运行时本身就是个对象(Java万物皆对象)
  • 换句话说,Class的实例就对应一个运行时类。言外之意,Class的实例无法被手动new出来
  • 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类

4. 获取Class的四种方式

4.1 调用运行时类的属性.class

image.png

4.2 通过运行时类的对象

image.png

4.3 调用Class的静态方法:forName

将类的完整路径传进去就行(从src下开始,不包含src)
image.png

4.4 使用类的加载器:ClassLoader

image.png