Java-反射(Reflect)

708 阅读4分钟

1、反射是一开始并不知道实例化对象是什么,则就无法使用new关键字来创建对象,这时候,我们就通过JDK提供的API进行反射调用。反射是运行时才知道要操作的类是什么,并且在运行时获取类的完整构造,并调用对应的方法。

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法。 Java反射机制主要提供了以下功能:

	在运行时构造任意一个类的对象
	在运行时获取任意一个类所具有的成员变量和方法
	在运行时调用任意一个对象的方法(属性)

Java 是一门面向对象的语言。在面向对象的世界里,万事万物皆对象,既然万事万物皆对象,那么我们的类是不是对象呢?我们写的每一个类都可以看成一个对象,是 java.lang.Class 类的对象。每一个类对应的Class放在哪里呢?当我们写完一个类的Java文件,编译成class文件的时候,编译器都会将这个类的对应的class对象放在class文件的末尾。里面可以理解保存了类的元数据信息,一个类的元数据信息包括有属性,方法,构造器,实现了接口等等,那么这些信息在Java里都有对应的类来表示。

2、Class 类

Class是一个类,封装了当前对象所对应的类的信息

3、类加载器、构造器、Method、Field

举例说明

//先创建一个Person 类
public class Person {
    String name;
    private int age;
    //包含一个带参的构造器和一个不带参的构造器
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("我是两个参构造方法");
    }

    public Person() {
        System.out.println("我是无参构造方法");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("This is setName");
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
        System.out.println("This is setAge");
    }

    //私有方法
    private void privateMethod(){
        System.out.println("This is private method");
    }
}

//测试类
public class Test{
     /*类加载器相关*/
    public static void testClassLoader() throws ClassNotFoundException {
            //1. 获取一个系统的类加载器(可以获取,当前这个类PeflectTest就是它加载的)
            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
            System.out.println("系统的类加载器 "+classLoader);
            //2. 获取系统类加载器的父类加载器(扩展类加载器,可以获取).
            classLoader = classLoader.getParent();
            System.out.println("系统类加载器的父类加载器 "+classLoader);
            //3. 获取扩展类加载器的父类加载器(引导类加载器,不可获取).
            classLoader = classLoader.getParent();
            System.out.println("扩展类加载器的父类加载器 "+classLoader);
            //4. 测试当前类由哪个类加载器进行加载(系统类加载器):
            Class<?> clazz = Class.forName("JavaGaoji.RefectFs.more.MyTestClassLoader");
            classLoader = clazz.getClassLoader();
            System.out.println("类加载器进行加载 "+classLoader);
    
            //5. 测试 JDK 提供的 Object 类由哪个类加载器负责加载(引导类)
            classLoader = Class.forName("java.lang.Object").getClassLoader();
            System.out.println("Object 类由哪个类加载器 " +classLoader );
    }

    /*构造器相关*/
    public static void testConstructor() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1、获取类;
        String className = "Refect.Person"; //类的全路径名称
//        Class<?> personClass = Class.forName(className);
        Class<Person> personClass = (Class<Person>) Class.forName(className);

        //获取所有构造方法
        Constructor<Person>[] constructors = (Constructor<Person>[]) personClass.getConstructors();
        for (int i = 0; i < constructors.length; i++) {
            System.out.println("构造方法"+i+" " + constructors[i]);
        }
        //具体获取构造方法
        //获取无参构造方法
        Constructor<Person> constructor = personClass.getConstructor();
        Object instance = constructor.newInstance();
        //获取有参构造方法
        Constructor<Person> constructor1 = personClass.getConstructor(String.class, int.class);
        Person niko =  constructor1.newInstance("Niko", 18);
        niko.setName("小明");
    }
    
     /*字段相关*/
     public static void testField() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        String className = "Refect.Person";
        //获取类
        Class<Person> personClass = (Class<Person>) Class.forName(className);

        //获取类中的所有字段
        System.out.println("获取类中的所有字段包括私有字段,不包括父类的字段");
        Field[] fields = personClass.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            System.out.println(field.getName());
        }

        System.out.println("==============");
        //获取之指定字段
        System.out.println("获取之指定字段");
        Field name = personClass.getDeclaredField("name");
        //给字段赋值
        System.out.println("给字段赋值");
        //获取对象
        Person person = personClass.newInstance();
        name.set(person,"Niko");
        System.out.println(person.getName());

        System.out.println("==============");
        //获取私有字段并赋值
        System.out.println("获取私有字段并赋值");
        Field age = personClass.getDeclaredField("age");
        age.setAccessible(true);
        age.set(person,18);
        System.out.println(person.getAge());
    }
    
     /*方法相关*/
    public static void testMethod() throws ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
        String className = "Refect.Person";
        //获取类
        Class<Person> personClass = (Class<Person>) Class.forName(className);

        //获取类中的所有方法,包括父类的方法, 不能获取私有的方法
        System.out.println("获取类中的所有方法,包括父类的方法, 不能获取私有的方法");
        Method[] methods = personClass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            System.out.println("类中的方法"+i +" "+ method.getName());
        }

        //获取类中所有的方法,且只获取当前类的方法,  包括自身的私有方法
        System.out.println("获取类中所有的方法,且只获取当前类的方法,  包括自身的私有方法");
        Method[] declaredMethods = personClass.getDeclaredMethods();
        for (int i = 0; i < declaredMethods.length; i++) {
            Method method = declaredMethods[i];
            System.out.println("类中的方法"+method);
//            Class<?>[] parameterTypes = method.getParameterTypes();
//            for (int j = 0; j < parameterTypes.length; j++) {
//                System.out.println("类中的方法"+method.getName() +" 参数 "+ parameterTypes[j]);
//            }
        }

        //第一个参数是方法名字 第二个参数是参数类型
        System.out.println("==================");
        Method method = personClass.getMethod("setName", String.class);
        System.out.println(method);
        //调用公共方法
        Person person = personClass.newInstance();
        //第一个参数为对象 后面是该方法的参数
        method.invoke(person,"Hello world");

        //调用私有方法
        Method privateMethod = personClass.getDeclaredMethod("privateMethod");
        //调用私有方法必须先调用此方法,传入 true
        privateMethod.setAccessible(true);
        privateMethod.invoke(person);
    }
    
      public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//        Test.testClassLoader();
//        Test.testConstrucTor();
//        Test.testMethod();
        Test.testField();
    }
}