【Java高级】利用反射获取非静态内部类有参(无参)构造方法 创建内部类对象 调用内部类方法 内部类全限定类名规律 getConstructor getMethod getField getClass

一、直接看如何使用:

(一)通过反射获取非静态内部类有参(无参)构造方法:

1、 获取无参构造方法+创建内部类对象:

Constructor<DogAndStudent.Student> studentConstructor = clazz.getConstructor(DogAndStudent.class);
DogAndStudent.Student studentForTest = (DogAndStudent.Student)studentConstructor.newInstance(new DogAndStudent());

说明:

1、DogAndStudent为外部类,Dog,Student为内部类。
2、利用getConstructor()获取非静态内部类构造方法时需要传入参数【外部类.class】
3、使用newInstance创建非静态内部类对象时需要传入外部类对象

参考:

Java内部类的全限定名规律
Java反射获取内部类的实例

2、获取有参构造方法:

Constructor<DogAndStudent.Student> studentMethod1 = clazz.getDeclaredConstructor(DogAndStudent.class, String.class, Integer.class, String.class, Date.class, dog1.getClass());

说明:

1、比无参构造方法多了所需参数的class,以及在首个参数位置的【父类.class】
2、这个父类.class为什么要写?具体原因我也不知道,某度也没有搜到获取有参数的构造方法的文章,所以是自己摸索的。可以通过getDeclaredConstructors()方法看到如下内容:

//public com.itqidian.cc.Homework_4.DogAndStudent$Student(com.itqidian.cc.Homework_4.DogAndStudent,java.lang.String,java.lang.Integer,java.lang.String,java.util.Date,com.itqidian.cc.Homework_4.DogAndStudent$Dog)

(二)通过反射得到的有参构造器创建非静态内部类对象

DogAndStudent.Student student = studentMethod1.newInstance(new DogAndStudent(), "888", (Integer)18, "18818818888", new Date(), dog1);

或者:

Object[] initargs = {new DogAndStudent(), "888", (Integer)18, "18818818888", new Date(), dog1};
DogAndStudent.Student student = studentMethod1.newInstance(initargs);//也可以

说明:

1、需要在所需要的参数前加上外部类对象new DogAndStudent()

(三)利用反射调用内部类对象的方法(非public及public)

//使用反射获取showInfo方法并调用
Method showInfoMethod = clazz.getMethod("showInfo");
showInfoMethod.invoke(student);
            
//使用反射获取walkAdog方法并调用
Method walkAdogMethod = clazz.getDeclaredMethod("walkAdog");
DogAndStudent.Dog doge = (DogAndStudent.Dog)walkAdogMethod.invoke(student);
Field ageField = doge.getClass().getDeclaredField("age");//★★★★注意要Declared★★★★
Field nameField = doge.getClass().getDeclaredField("name");//★★★★注意要Declared★★★★
ageField.setAccessible(true);
nameField.setAccessible(true);
System.out.println("这只狗芳龄:"+ageField.get(doge));
System.out.println("昵称是:"+nameField.get(doge));

说明:

1、getMethod()能获取public修饰方法。
2、getMethods()能获取所有的public修饰方法(包括继承的方法)。
3、getDeclaredMethod()能获取所有的方法(包括private修饰的)。
4、getDeclaredMethods()能获取所有的方法(但不包括继承的方法)。
5、利用反射调用private修饰的方法或者属性时,要先设置方法或属性的可见性为true:xxxx.setAccessible(true)

二、作业描述:

定义如下的类:

public class Dog{
    private int age;
    private String name;
}
public class Student{
    private String no;
    private Integer age;
    private String tel;
    private Date birth;
    private Dog dog;
    //无参数构造
    public Student(){}
    //全参构造方法
    public Student(.....){....}
    void showInfo(){ 输出所有信息 }
    
    Dog walkAdog(){return dog;}
    
    // setter和getter省略
}

[1]使用反射创建一个Student对象。
[2]给创建的对象的所有属性赋值。
[3]使用反射获取shwoInfo方法,并且执行。
[4]使用反射获取walkAdog方法, 并且执行。将执行结果转换为Dog类型。
[5]利用全参构造方法创建一个Student对象。

三、代码

DogAndStudent类:

/**
 * @author cc
 * @description
 */
package com.itqidian.cc.Homework_4;

import java.util.Date;

public class DogAndStudent {
    public DogAndStudent() {
    }

    public class Dog{
        private int age;
        private String name;
    }
    
    public class Student{
        private String no;
        private Integer age;
        private String tel;
        private Date birth;
        private Dog dog;

        Dog walkAdog(){
            return this.dog;
        }
        
        //无参数构造方法
        public Student() {
        }

        //全参构造方法
        public Student(String no, Integer age, String tel, Date birth, Dog dog) {
            this.no = no;
            this.age = age;
            this.tel = tel;
            this.birth = birth;
            this.dog = dog;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "no='" + no + '\'' +
                    ", age=" + age +
                    ", tel='" + tel + '\'' +
                    ", birth=" + birth +
                    ", dog=" + dog +
                    '}';
        }

        public void showInfo(){
            System.out.println(this.toString());
        }

        // setter和getter
        public String getNo() {
            return no;
        }

        public void setNo(String no) {
            this.no = no;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        public String getTel() {
            return tel;
        }

        public void setTel(String tel) {
            this.tel = tel;
        }

        public Date getBirth() {
            return birth;
        }

        public void setBirth(Date birth) {
            this.birth = birth;
        }

        public Dog getDog() {
            return dog;
        }

        public void setDog(Dog dog) {
            this.dog = dog;
        }
    }
}

测试类:

/**
 * @author cc
 * @description
 */
package com.itqidian.cc.Homework_4;

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

public class Ex {
    public static void main(String[] args) {
        //[1]使用反射创建一个Student对象。
        //[2]给创建的对象的所有属性赋值。
        //[3]使用反射获取shwoInfo方法,并且执行。
        //[4]使用反射获取walkAdog方法, 并且执行。将执行结果转换为Dog类型。
        //[5]利用全参构造方法创建一个Student对象。
        Class clazz = null;
        Class clazz1 = null;
        Class clazz2 = null;

        //获取Class对象:
        try {
            //法一:通过Class的forName获取 需要知道成员内部类 匿名内部类 局部内部类的命名规则。
            clazz = Class.forName("com.itqidian.cc.Homework_4.DogAndStudent$Student");
            //法二:通过类的静态成员变量class获取
            clazz1 = DogAndStudent.Student.class;
            //法三:通过类对象的getClass()获取
            clazz2 = new DogAndStudent().new Student().getClass();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(clazz == clazz1 && clazz1 == clazz2 && clazz == clazz2);//true
//        System.out.println(clazz.toString());
        
        //创建类对象
//        法一:newInstance();通过无参数的构造方法创建这个类的一个对象。
//          在没有指定泛型的情况下创建的对象类型是Object
//          这个类必须有无参数的构造方法,如果没有就报错。
        try {
//            ★★★★★反射产生非静态内部类的实例化对象
//            ★★★★★要实例化非静态的内部类对象,必须先实例化外部类的对象。
//            ★★★★★而法一直接利用Class对象的newInstance()创建实例对象,括号中无法传入外部类对象
//            ★★★★★所以只能通过Constructor对象的newInstance()创建
            //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★这里要传入一个外部类★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
//            1、由于成员内部类对象的创建依赖于外部类对象,持有指向外部类对象的引用。
//            所以在反射构造成员内部类的时候一定要通过获取构造器再调用构造器的newInstance方法,
//            其中必须要传入外部类的Class和实例。
// https://blog.csdn.net/ldstartnow/article/details/52782420?spm=1001.2101.3001.6650.3&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3.pc_relevant_antiscanv2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-3.pc_relevant_antiscanv2&utm_relevant_index=5
            Constructor<DogAndStudent.Student> studentConstructor = clazz.getConstructor(DogAndStudent.class);
            //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
            DogAndStudent.Student studentForTest = (DogAndStudent.Student)studentConstructor.newInstance(new DogAndStudent());
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        //法二:我们可以通过Constructor提供的API获取构造方法的访问权限和参数列表信息。
        try {
            //创建dog类对象:dog1
            Class DogClass = Class.forName("com.itqidian.cc.Homework_4.DogAndStudent$Dog");
            Constructor<DogAndStudent.Dog> dogConstructor = DogClass.getDeclaredConstructor(DogAndStudent.class);
            DogAndStudent.Dog dog1 = dogConstructor.newInstance(new DogAndStudent());
            //初始化dog1
            Field dogAge = DogClass.getDeclaredField("age");
            Field dogName = DogClass.getDeclaredField("name");
            dogAge.setAccessible(true);
            dogName.setAccessible(true);
            dogAge.set(dog1, 3);
            dogName.set(dog1, "豆豆");

            //获取Student类的构造方法
            //★★★★★★★★原来如此少了一个父类的Class:com.itqidian.cc.Homework_4.DogAndStudent★★★★★★★★
            Constructor<DogAndStudent.Student> studentMethod1 = clazz.getDeclaredConstructor(DogAndStudent.class, String.class, Integer.class, String.class, Date.class, dog1.getClass());

            //★★★★forTest★★★★
//            Constructor[] studentMethod = clazz.getDeclaredConstructors();
            //public com.itqidian.cc.Homework_4.DogAndStudent$Student(com.itqidian.cc.Homework_4.DogAndStudent,java.lang.String,java.lang.Integer,java.lang.String,java.util.Date,com.itqidian.cc.Homework_4.DogAndStudent$Dog)
            //原来如此少了一个父类的Class:com.itqidian.cc.Homework_4.DogAndStudent
//            System.out.println(studentMethod[0]);
                    
            //创建Student对象
            //★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
//            Object[] initargs = {new DogAndStudent(), "888", (Integer)18, "18818818888", new Date(), dog1};
//            DogAndStudent.Student student = studentMethod1.newInstance(initargs);//也可以
            DogAndStudent.Student student = studentMethod1.newInstance(new DogAndStudent(), "888", (Integer)18, "18818818888", new Date(), dog1);

            //使用反射获取showInfo方法并调用
            Method showInfoMethod = clazz.getMethod("showInfo");
            showInfoMethod.invoke(student);
            
            //使用反射获取walkAdog方法并调用
            Method walkAdogMethod = clazz.getDeclaredMethod("walkAdog");
            DogAndStudent.Dog doge = (DogAndStudent.Dog)walkAdogMethod.invoke(student);
            Field ageField = doge.getClass().getDeclaredField("age");//★★★★注意要Declared★★★★
            Field nameField = doge.getClass().getDeclaredField("name");//★★★★注意要Declared★★★★
            ageField.setAccessible(true);
            nameField.setAccessible(true);
            System.out.println("这只狗芳龄:"+ageField.get(doge));
            System.out.println("昵称是:"+nameField.get(doge));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

四、总结

这道题完全可以将两个类拆分成单独的类,但是我自讨苦吃,整了半天才整明白,网上相关也只能搜到如何利用无参构造函数创建非静态内部类对象,自己摸索了很久才解决,以供大家学习。

你可能感兴趣的:(Java高级,java,后端,反射)