Mastering Java Reflection: Tips and Tricks for Advanced Developers

1. Definition of reflection

The definition of reflection: Java's reflection mechanism is that in the running state, for any class, you can know all the properties and methods of this class; for any object, you can call any of its methods and properties. Since we can get it, then we You can modify part of the type information. This function of dynamically obtaining information and dynamically calling object methods is called the reflection mechanism.

The reflection mechanism simply means that any method and property in a class or object (whether public or privet modified) can be obtained in the running state.

For example: Assuming that a university starts school, the university students have to take various means of transportation to come to the school during the period when the school starts. Some students will go to school by plane, train, or bus. Students who use tools have to go through the security check at the corresponding station before they can board the corresponding means of transportation. Then when passing the security check, they need to put the suitcase and the things they carry into the security check machine for scanning. When scanning, they can pass the corresponding The device sees whether there are prohibited items in the suitcase and carry-on items

2. The purpose of reflection

  • When some properties and methods in a class are private or only open to system applications, reflection can be used to obtain the required private properties and methods

  • The most important use of reflection is to develop various general frameworks

3. Important classes related to reflection

class name

use

class class

An entity representing a class, representing classes and interfaces in a running Java application

Field class

Represents the member variables of the class/attributes of the class

Method class

method of the delegate class

Constructor class

Delegate class constructor

4. The origin of the reflection mechanism: the Class class

Class represents the entity of a class, and represents classes and interfaces in a running Java application

After the Java file is compiled, it will generate a .class file, and the JVM will interpret the .class file at this time. The compiled Java file .class is also parsed into an object by the JVM, and this object is java.lang.class. When the program is running, each java file eventually becomes an instance of the Class class object. We can apply to this instance through the reflection mechanism of Java to get or even add and change the attributes and actions of this class, making this class a dynamic class

5. Related methods of the Class class

Commonly used methods for obtaining classes

方法

用途

getClassLoader()

获得类的加载器

getDeclareClasses()

返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)

forName(String classNme)

根据类名返回类的对象

newInstance()

创建类的实例

getName()

获得类的完整路径名字

常用获得类中属性相关的方法(以下方法返回值为Field)

方法

用途

getField(String name)

获得某个公有的属性对象

getFields()

获得所有公有的属性对象

getDeclaredField(String name)

获得某个属性对象

getDeclaredFields()

获得所有属性对象

获得类中注解相关的方法

方法

用途

getAnnotation(Class annotationClass)

返回该类中与参数类型匹配的公有注解对象

getAnnotations()

返回该类所有的公有注解对象

getDeclaredAnnotation(Class annotationClass)

返回该类中与参数类型匹配的所有注解对象

getDeclaredAnnotations()

返回该类所有的注解对象

获得类中方法相关的方法 (以下方法返回值为Method 相关)

方法

用途

getMethod(String name,Class...<?> parameterTypes)

获得该类某个公有方法

getMethod()

获得该类所有公有的方法

getDeclaredMethod(String name,Class...<?> parameterTypes)

获得该类某个方法

getDeclaredMethod()

获得该类所有方法

获得类中构造器相关的方法(以下方法返回值为Constructor相关)

方法

用途

getConstructor(Class...<?> parameterTypes )

获得该类中与参数类型匹配的公有构造方法

getConstructors()

获得该类的所有公有构造方法

getDeclaredConstructor(Class...<?> parameterTypes)

获得该类中与参数类型匹配的构造方法

getDeclaredConstructors()

获得该类所有构造方法

6、 获得 Class 对象

我们想要进行反射,首先得拿到需要反射类的Class对象,通过 Class 对象的核心方法,来进行反射。

获得Class对象分别有三种方法:

  • 使用类对象的 getClass() 方法

  • 使用 .class 方法,仅时候在编译前就已经明确要操作的Class

  • 使用Class.forName("类得全路径名"),这个forName是Class这个类的静态方法,这个获取Class对象的前提条件就是知道类的全路径名

示例:

public class Student {
    private String name = "张三";//私有属性
    public int age = 18;//公共属性
    //不带参数的构造方法
    public Student(){
        System.out.println("Student()");
    }
    //带参数的私有构造方法
    private Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("Student(String,name)");
    }
    //私有方法
    private void eat(){
        System.out.println("i am eat");
    }
    //公共方法
    public void sleep(){
        System.out.println("i am sleep");
    }
    //带有参数的私有方法
    private void function(String str) {
        System.out.println(str);
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

现在我们就通过获取 Class 对象的三种方法,分别来获取上述的 Student 类的 Class 对象

使用类对象的 getClass() 方法获取:

public static void main(String[] args) {
        Student student = new Student();
        Class<?> s1 = student.getClass();
    }

使用 .class 方法获取:

直接通过 类名.class 的方式获得到的Class对象的方法最为安全可靠,程序性能也会更高,直接通过 类型.class 的方式获得到,也就说明任何一个类都有一个隐含的静态成员变量class

public static void main(String[] args) {
        Class<?> s2 = Student.class;
    }

使用Class.forName("类得全路径名") 方法获取:

通过 Class 对象的 forName() 静态方法来获取,可能会抛出 ClassNotFoundException 异常

public static void main(String[] args) {
        Class<?> s3 = null;
        try {
            s3 = Class.forName("Student");//这里是类的全路径,如果有包需要加包的路径
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

注意:一个类在 JVM中只会有一个 Class 实例,那么也就是说上面我们获取的 s1、s2、s3 这些 Class 对象,其实都是一个 Class 对象

System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s2.equals(s3));

打印结果:

7、 反射的使用

我们目前已经知道了如何获取到一个类的Class实例,那么接下来我们就通过 Class 实例来进行反射的使用

我们还是使用上述的 Student 类来进行反射的使用

7.1 通过反射创建一个 Student 对象

1、通过公共构造方法创建对象

public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class<?> studentClass = Student.class;//获取类的Class实例
        Object objectStudent = studentClass.newInstance();//通过Class实例,创建一个对象
        Student student = (Student) objectStudent;
        System.out.println("获得的学生对象:"+student);
    }

2、通过私有构造方法创建对象

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> studentClass = Student.class;
        Constructor<?> declaredConstructorStudent = studentClass.getDeclaredConstructor(String.class,int.class);
        declaredConstructorStudent.setAccessible(true);//设置为true后可修改访问权限
        Object objectStudent = declaredConstructorStudent.newInstance("李四",18);
        Student student = (Student)objectStudent;
        System.out.println(student);
    }

7.2 通过反射获取私有属性

public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        Class<?> studentClass = Student.class;
        Field field = studentClass.getDeclaredField("name");
        field.setAccessible(true);
        Object objectStudent = studentClass.newInstance();
        Student student = (Student)objectStudent;
        String name = (String) field.get(student);
        System.out.println(name);
    }

7.3 通过反射获取私有方法

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> studentClass = Student.class;
        Method method = studentClass.getDeclaredMethod("function",String.class);
        System.out.println("私有方法的方法名:"+method.getName());
        method.setAccessible(true);
        Object objectStudent = studentClass.newInstance();
        Student student = (Student)objectStudent;
        method.invoke(student,"私有方法的参数");
    }

注:反射机制不能反射枚举

Guess you like

Origin blog.csdn.net/m0_66488562/article/details/128924743