Java反射机制笔记

反射机制作用:
1.在运行中分析类的能力;
2.在运行中查看对象;
3.实现通用的数组操作代码;
4.利用Method对象操作函数;
5.利用Field对象操作属性。

使用反射机制主要用于工具构造者,而不是应用程序员。

定义一个在运行中反射的类:ReflectClass.java

package com.ez;

import java.io.Serializable;
import java.util.RandomAccess;

//这三个接口并不需要实现任何方法,所以就当测试吧。
public class ReflectClass implements Serializable, RandomAccess, Cloneable {

    private static final long serialVersionUID = -428410635246468432L;

    private String name;
    private int age;
    private int money;

    private String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    // 在反射条用方法的时候,无参构造函数不能省略,否则报错。
    public ReflectClass() {

    }

    // 至少有一个name属性
    // 年纪默认20
    // 工资默认2000
    public ReflectClass(String name) {
        this(name, 20);
    }

    public ReflectClass(String name, int age) {
        this(name, age, 2000);
    }

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getMoney() {
        return money;
    }

    public void doubleSalary() {
        this.money = money * 2;
    }

    // 添加下面两个方法供反射机制调用方法
    public void reflect1() {
        System.out.println("Java 反射机制 - 调用某个类的方法1.");
    }

    public void reflect2(int age, String name) {
        System.out.println("Java 反射机制 - 调用某个类的方法2.");
        System.out.println("age -> " + age + ". name -> " + name);
    }

    @Override
    public String toString() {
        return "[name:" + name + "\n" + //
                "age:" + age + "\n" + //
                "money:" + money + "]\n";//
    }
}

编写一个运行类:Main.java

package com.ez;

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

public class Main {

    public static void main(String[] args) throws Exception {

        // 1、通过实例对象获取包名
        ReflectClass test = new ReflectClass("luopan");
        System.out.println(test.getClass().getName());// 输出:com.ez.ReflectClass

        // 2、定义三个类对象,通过三种方式获取对象实例
        Class<?> class1 = null;
        Class<?> class2 = null;
        Class<?> class3 = null;

        class1 = Class.forName("com.ez.ReflectClass");
        class2 = new ReflectClass("weize").getClass();
        class3 = ReflectClass.class;
        System.out.println("class1=" + class1.getName());// 输出:class1=com.ez.ReflectClass
        System.out.println("class2=" + class2.getName());// 输出:class2=com.ez.ReflectClass
        System.out.println("class3=" + class3.getName());// 输出:class3=com.ez.ReflectClass

        // 3、获得父类信息【父类只有一个】
        Class<?> parentClass = class1.getSuperclass();
        System.out.println("parentClass=" + parentClass.getName());// 输出:parentClass=java.lang.Object

        // 4、获得接口信息【接口有多个,所以自然而然是一个数组了】
        Class<?>[] interfaces = class1.getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            System.out.printf("interface%d=%s \n", i + 1, interfaces[i]);
        }

        // 5、获取全部的构造方法【构造函数数量不是唯一的,所以是一个数组】
        Constructor<?> constructor[] = class1.getConstructors();
        for (int i = 0; i < constructor.length; i++) {
            // 遍历每个构造函数,并且获取到每个构造函数的参数类型。【由于参数格式不是唯一的,所以是一个数组】
            Class<?> clazz[] = constructor[i].getParameterTypes();
            for (int j = 0; j < clazz.length; j++) {
                if (j == clazz.length - 1)
                    System.out.print(clazz[j].getName());
                else
                    System.out.print(clazz[j].getName() + ",");
            }
            System.out.println();
        }

        // 6、根据获取得到的构造函数个数以及参数类型,实例化对象
        // 由于构造函数的顺序不是固定的,所以可以根据控制台打印的信息,手动创建实例对象

        // 7、获取全部属性【属性数量不唯一,所以是数组】
        Field[] field = class1.getDeclaredFields();
        for (int i = 0; i < field.length; i++) {
            // 每个属性都是由权限修饰符和类型组成
            int mo = field[i].getModifiers();
            String modiString = Modifier.toString(mo);
            Class<?> type = field[i].getType();
            System.out.println(modiString + " " + type.getName() + " "
                    + field[i].getName() + ";");
        }
        System.out.println();

        // 8、获取全部方法【方法数量不唯一,所以是数组】
        Method methods[] = class1.getMethods();
        for (int i = 0; i < methods.length; i++) {

            // 获取方法的权限修饰符
            int mo = methods[i].getModifiers();
            String modiString = Modifier.toString(mo);
            System.out.print(modiString + " ");

            // 获取方法返回类型【返回类型只能是一种】
            Class<?> returnType = methods[i].getReturnType();
            System.out.print(returnType.getName() + " ");

            System.out.print(methods[i].getName() + "(");

            // 获取方法参数类型【参数数量不唯一,所以是数组】
            Class<?> parameterType[] = methods[i].getParameterTypes();
            for (int j = 0; j < parameterType.length; j++) {
                System.out.print(parameterType[j].getName() + " " + "arg" + j);
                if (j < parameterType.length - 1) {
                    System.out.print(",");
                }
            }

            // 获取方法的异常抛出类型【异常的数量不唯一,所以是数组】
            Class<?> exce[] = methods[i].getExceptionTypes();
            if (exce.length > 0) {
                System.out.print(") throws ");

                for (int k = 0; k < exce.length; k++) {
                    System.out.print(exce[k].getName() + " ");
                    if (k < exce.length - 1) {
                        System.out.print(",");
                    }
                }
            } else {
                System.out.print(")");
            }
            System.out.println();
        }

        // 9、使用反射机制调用方法
        Class<?> clazz = Class.forName("com.ez.ReflectClass");

        // 调用TestReflect类中的reflect1方法
        Method method = clazz.getMethod("reflect1");
        method.invoke(clazz.newInstance());

        // 调用TestReflect类中的reflect2方法
        method = clazz.getMethod("reflect2", int.class, String.class);
        method.invoke(clazz.newInstance(), 20, "张三");

        // 10、使用放射机制操作属性
        Class<?> clazz1 = Class.forName("com.ez.ReflectClass");
        Object obj = clazz1.newInstance();
        // 可以直接对 private 的属性赋值
        Field field1 = clazz1.getDeclaredField("test");
        field1.setAccessible(true);
        field1.set(obj, "Java反射机制");
        System.out.println(field1.get(obj));

    }
}

在这个练习中,我遇到了一个很棘手的问题,并且很难看出问题的。错误异常如下:

at java.lang.Class.newInstance0(Unknown Source)

这是因为我添加了3个有参构造函数,这样就会导致无参构造函数不被默认创建。
但是,在Class类中,

private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);

这个方法会去寻找无参构造函数,就会跑出这个异常。

解决方案就是:手动添加一个无参构造函数。

猜你喜欢

转载自blog.csdn.net/qq_36006553/article/details/71141648