Java反射相关类以及底层原理

文章目录

  • 一、Java反射核心类:
    • 1、Class类:
    • 2、Constructor类:
    • 3、Field类:
    • 4、Method类:
  • 二、反射的底层原理

一、Java反射核心类:

1、Class类:

表示Java类的实例,可以用于获取类的信息,如类名、父类、接口、字段、方法等。可以使用Class.forName()方法根据类名获取Class对象,或者使用对象的getClass()方法获取Class对象。

下面是一个简单的示例代码,演示如何使用反射获取类的信息:

public class Main {
    public static void main(String[] args) {
        try {
            // 使用Class.forName()方法获取Class对象
            Class<?> clazz = Class.forName("com.example.MyClass");

            // 获取类名
            String className = clazz.getName();
            System.out.println("Class Name: " + className);

            // 获取父类
            Class<?> superClass = clazz.getSuperclass();
            System.out.println("Super Class: " + superClass.getName());

            // 获取接口
            Class<?>[] interfaces = clazz.getInterfaces();
            System.out.println("Implemented Interfaces:");
            for (Class<?> interfaceClass : interfaces) {
                System.out.println(interfaceClass.getName());
            }

            // 获取字段
            Field[] fields = clazz.getDeclaredFields();
            System.out.println("Fields:");
            for (Field field : fields) {
                System.out.println(field.getName());
            }

            // 获取方法
            Method[] methods = clazz.getDeclaredMethods();
            System.out.println("Methods:");
            for (Method method : methods) {
                System.out.println(method.getName());
            }

            // 获取构造器
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            System.out.println("Constructors:");
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

class MyClass extends BaseClass implements MyInterface {
    private int id;
    public String name;

    public MyClass(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public void printInfo() {
        System.out.println("ID: " + id);
        System.out.println("Name: " + name);
    }
}

class BaseClass {
    // 父类
}

interface MyInterface {
    // 接口
}

输出结果:

Class Name: com.example.MyClass
Super Class: com.example.BaseClass
Implemented Interfaces:
com.example.MyInterface
Fields:
id
name
Methods:
printInfo
Constructors:
com.example.MyClass

2、Constructor类:

表示类的构造方法,可以用于创建类的实例。可以使用Class类的getConstructor()方法或getDeclaredConstructor()方法获取Constructor对象,然后使用newInstance()方法创建实例。

下面是一个简单的示例演示如何使用构造方法创建类的实例:

import java.lang.reflect.Constructor;

class MyClass {
    private String name;

    public MyClass(String name) {
        this.name = name;
    }

    public void printName() {
        System.out.println("Name: " + name);
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取 MyClass 类的构造方法
        Constructor<MyClass> constructor = MyClass.class.getConstructor(String.class);

        // 使用构造方法创建类的实例
        MyClass myClass = constructor.newInstance("John");

        // 调用实例方法
        myClass.printName();
    }
}

在上面的示例中,我们首先使用MyClass.class.getConstructor(String.class)获取了MyClass类的构造方法对象,该构造方法接受一个String类型的参数。然后,我们使用constructor.newInstance(“John”)来创建一个实例,参数"John"将作为构造方法的参数传递进去。最后,我们调用了实例方法printName()来打印实例的名称。

3、Field类:

表示类的字段,可以用于获取和设置字段的值。可以使用Class类的getField()方法或getDeclaredField()方法获取Field对象,然后使用get()方法获取字段的值,或者使用set()方法设置字段的值。

下面是一个简单的示例演示如何使用字段获取和设置字段的值:

import java.lang.reflect.Field;

class MyClass {
    public String name;
    private int age;

    public MyClass(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void printInfo() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建 MyClass 实例
        MyClass myClass = new MyClass("John", 25);

        // 获取 MyClass 类的 name 字段
        Field nameField = MyClass.class.getField("name");

        // 获取 MyClass 类的 age 字段
        Field ageField = MyClass.class.getDeclaredField("age");
        ageField.setAccessible(true); // 设置私有字段可访问

        // 获取字段的值
        String nameValue = (String) nameField.get(myClass);
        int ageValue = (int) ageField.get(myClass);

        System.out.println("Name: " + nameValue);
        System.out.println("Age: " + ageValue);

        // 设置字段的值
        nameField.set(myClass, "Alice");
        ageField.set(myClass, 30);

        myClass.printInfo();
    }
}

在上面的示例中,我们创建了一个MyClass类的实例,并且使用getField()方法获取了name字段的Field对象,使用getDeclaredField()方法获取了age字段的Field对象。getDeclaredField()方法可以获取私有字段,但私有字段默认是不可访问的,因此我们需要调用setAccessible(true)来设置私有字段可访问。

然后,我们使用get()方法分别获取了name字段和age字段的值,并使用set()方法将name字段的值设置为"Alice",将age字段的值设置为30。最后,我们调用printInfo()方法来打印字段的值,验证字段的值是否已经被修改。注意,需要进行类型转换来获取和设置字段的值。

4、Method类:

表示类的方法,可以用于调用方法。可以使用Class类的getMethod()方法或getDeclaredMethod()方法获取Method对象,然后使用invoke()方法调用方法。

下面是一个使用反射调用类的方法的示例代码:

import java.lang.reflect.Method;

class MyClass {
    public void myMethod() {
        System.out.println("调用了myMethod方法");
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取MyClass类的Class对象
        Class<?> clazz = MyClass.class;

        // 获取myMethod方法的Method对象
        Method method = clazz.getMethod("myMethod");

        // 创建MyClass类的实例
        MyClass myObj = new MyClass();

        // 调用myMethod方法
        method.invoke(myObj);
    }
}

输出结果:

调用了myMethod方法

在上面的代码中,我们首先通过MyClass.class获取了MyClass类的Class对象。然后使用getMethod()方法传入方法名来获取myMethod方法的Method对象。

接着,我们创建了MyClass类的实例myObj。

最后,我们使用invoke()方法来调用myMethod方法,传入myObj作为方法的调用者。这样就成功地调用了myMethod方法。

需要注意的是,如果myMethod方法是私有方法或者是继承自父类的方法,需要使用getDeclaredMethod()方法获取Method对象。并且在调用invoke()方法之前,需要先调用setAccessible(true)来设置方法的可访问性。

二、反射的底层原理

  1. 在Java程序的执行过程中,首先需要将源代码进行编译,生成对应的字节码文件(.class文件)。然后,JVM会加载这些字节码文件,并在方法区中创建对应的类信息,包括类的名称、父类、接口、字段、方法等。

  2. 反射就是通过获取这些类信息的方式,来实现对类的动态操作。通过获取类的Class对象,可以获取类的名称、父类、接口等信息。
    通过Class对象的方法,可以获取类的构造器、字段、方法等成员信息,并可以动态地创建对象、调用方法、访问字段等。

  3. 反射的机制使得程序能够在运行时动态地获取和操作类的信息,而不需要在编译时就确定类的结构。这为框架的开发、动态代理、配置文件的读取等提供了便利。但是需要注意的是,反射的使用可能会带来一定的性能损耗,因此在性能要求高的场景中需要谨慎使用。

你可能感兴趣的:(《Java基础》专栏,java)