Java反射技术

1 阅读9分钟

说明:反射是通过对类的字节码(.class)文件进行解析,实现对javaBean对象操作的技术。使用反射的好处是,所有的javaBean组成都是相同的(成员变量、成员方法、构造器),通过反射解析.class文件,可以把多种类型的对象同时解析出来,实现用同一个配置文件(如properties)实例化多个不同类型对象的效果。另外,反射还可以无视权限修饰符,访问javaBean中的任意成员。

总结,使用反射的好处:(1)通用,创建不同的对象可以动态变化;(2)不受成员权限修饰符的限制 在这里插入图片描述

一、获取Class对象

方式一:类名.class

	// 方式一:类名.class
	Class<Student> studentClass = Student.class;
	System.out.println(studentClass);

在这里插入图片描述

方式二:static Class forName(String fullNameWithPackage)

需要注意的是,forName()的参数是类的全类名;最前面的Class后面的泛型可去掉

	// 方式二:Class forName(String fullNameWithPackage)
	Class studentClass = Class.forName("com.essay.Student");
	System.out.println(studentClass);

在这里插入图片描述 在这里插入图片描述

方式三:new Object().getClass()

	// 方式三:new Object().getClass()
	Class<? extends Student> studentClass = new Student().getClass();
	System.out.println(studentClass);

在这里插入图片描述

小结

这三种方式获取方式,推荐使用第二种

另外值得一提的是,这三种获取方式获取到的Class对象,都是同一个,比较三者的地址值,都是true

	// 方式一:类名.class
	Class<Student> studentClass1 = Student.class;
	
	// 方式二:Class forName(String fullNameWithPackage)
	Class studentClass2 = Class.forName("com.essay.Student");
	
	// 方式三:new Object().getClass()
	Class<? extends Student> studentClass3 = new Student().getClass();
	
	System.out.println(studentClass1 == studentClass2);
	System.out.println(studentClass1 == studentClass3);

在这里插入图片描述

二、通过Class对象获取Constructor构造器对象

这里使用到的Student对象类代码如下:

public class Student {
    private String name;
    private int age;
    private String sex;

    public Student() {
    }

    public Student(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    private Student(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }


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

2.1、getConstructors():获取所有公共构造器对象

	// 获取学生类的Class对象(用第二种获取Class对象的方式)
	Class studentClass = Class.forName("com.essay.Student");
	
	// getConstructors():获取所有公共构造器对象
	Constructor[] constructors1 = studentClass.getConstructors();
	System.out.println("--------------公共构造器对象如下--------------");
	for (Constructor constructor : constructors1) {
	    System.out.println(constructor);
	}

在这里插入图片描述

2.2、getDeclaredConstructors():获取所有构造器对象(公共+非公共的)

	// 获取学生类的Class对象(用第二种获取Class对象的方式)
	Class studentClass = Class.forName("com.essay.Student");
	
	// getDeclaredConstructors():获取所有构造器对象
	Constructor[] constructors = studentClass.getDeclaredConstructors();
	System.out.println("--------------所有构造器对象(公共+非公共)如下--------------");
	for (Constructor constructor : constructors) {
	    System.out.println(constructor);
	}

在这里插入图片描述

2.3、getConstructor(Class<?>... parameterTypes):获取一个指定的公共构造器对象

	// 获取学生类的Class对象(用第二种获取Class对象的方式)
	Class studentClass = Class.forName("com.essay.Student");
	
	// getConstructor(Class<?>... parameterTypes):获取一个指定的带两个参数的公共构造器对象
	Constructor constructor = studentClass.getConstructor(String.class, String.class);
	System.out.println("--------------指定获取Student类带两个参数的公共构造器对象--------------");
	System.out.println(constructor);

在这里插入图片描述

2.4、getDeclaredConstructor(String.class, int.class, String.class):获取一个指定的私有构造器对象

需要注意的是,这种方式当然也可以获取指定的私有构造器对象

	// 获取学生类的Class对象(用第二种获取Class对象的方式)
	Class studentClass = Class.forName("com.essay.Student");
	
	// getDeclaredConstructor(Class<?>... parameterTypes):获取一个指定的带三个参数的私有构造器对象
	Constructor constructor = studentClass.getDeclaredConstructor(String.class, int.class, String.class);
	System.out.println("--------------指定获取Student类私有的带三个参数的构造器对象--------------");
	System.out.println(constructor);

在这里插入图片描述

三、通过用获取到的Constructor构造器,实例化对象

3.1、获取公共无参构造,并通过其创建所属类(Student)的对象

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的构造方法对象
	Constructor constructor = studentClass.getConstructor();
	
	// 3.使用当前类(Student)的constructor对象的newInstance方法创建当前类(Student)
	// 这里就相当于不用反射技术的:new Student();
	Object o = constructor.newInstance();
	
	// 打印对象,调用对象的toString()方法
	System.out.println(o);

在这里插入图片描述

3.2、反射获取公共一个参数构造,并通过其创建所属类(Student)的对象

        // 1.获取当前类(Student)的Class对象
        Class studentClass = Class.forName("com.essay.Student");

        // 2.通过当前类(Student)的Class对象获取当前类(Student)的构造方法对象
        Constructor constructor = studentClass.getConstructor(String.class, String.class);

        // 3.使用当前类(Student)的constructor对象的newInstance方法创建当前类(Student)
        // 这里就相当于不用反射技术的:new Student("张三", "男");
        Object o = constructor.newInstance("张三", "男");

        // 打印对象,调用对象的toString()方法
        System.out.println(o);

在这里插入图片描述

3.3、反射获取私有全参构造,并通过其创建所属类(Student)的对象

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的构造方法对象
	Constructor constructor = studentClass.getDeclaredConstructor(String.class, int.class, String.class);
	
	// 对于私有的成员,想要操作,需要先暴力反射。否则会报非法访问异常:IllegalAccessException
	constructor.setAccessible(true);
	
	// 3.使用当前类(Student)的constructor对象的newInstance方法创建当前类(Student)
	// 这里就相当于不用反射技术的:new Student("张三", "男");
	Object o = constructor.newInstance("张三", 29, "男");
	
	// 打印对象,调用对象的toString()方法
	System.out.println(o);

在这里插入图片描述

3.4、对于3.1 获取公共无参构造,并通过其创建所属类(Student)的对象的情况,可以直接使用Class提供的方法

但idea在方法上有横线提示,这种方法已过时,不推荐使用

	// 获取学生类的Class对象(用第二种获取Class对象的方式)
	Class studentClass = Class.forName("com.essay.Student");
	
	// Class对象提供了便捷创建所属类对象的方法:newInstance()
	Object o = studentClass.newInstance();
	
	// 打印对象,调用对象的toString()方法
	System.out.println(o);

在这里插入图片描述

小结

对于私有的成员,想要操作,需要先暴力反射。否则会报非法访问异常:IllegalAccessException

四、通过Class对象获取Field成员变量对象

4.1、getDeclaredFields():获取所有成员变量对象(公共+非公共)

	// 获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// getDeclaredFields():获取所有成员变量对象(公共+非公共)
	Field[] fields = studentClass.getDeclaredFields();
	
	System.out.println("--------------Student对象的所有成员变量对象如下--------------");
	
	// 遍历打印
	for (Field field : fields) {
	    System.out.println(field);
	}

在这里插入图片描述

4.2、getField(String name):获取指定的公共成员变量对象

博主这里先把Student类中的name属性的权限修饰符设置为public

    // 将name的修饰符设置为public
    public String name;
    private int age;
    private String sex;
	// 获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// getField(String name):获取指定的公共成员变量对象
	Field name = studentClass.getField("name");
	
	System.out.println("--------------Student对象成员变量name对象如下--------------");
	
	System.out.println(name);

在这里插入图片描述

4.3、getDeclaredField(String name):获取指定的任意一个(公共或私有等)成员变量对象

	// 获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// getDeclaredField(String name):获取指定的任意一个(公共或私有等)成员变量对象
	Field age = studentClass.getDeclaredField("age");
	
	System.out.println("--------------Student对象成员变量age对象如下--------------");
	
	System.out.println(age);

在这里插入图片描述

五、使用获取到的Field对象为成员变量赋值或者取值

5.1、获取公共的成员变量name并使用

需要注意,在4.2那里,我将Student类name属性权限修饰符改为了public

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的属性Field对象
	Field name = studentClass.getField("name");
	
	// 3.1 准备一个学生对象
	Object o = studentClass.newInstance();
	
	// 3.2 为成员变量赋值
	// void set(Object 所属类的对象, Object 要赋的值)
	name.set(o, "张三");
	
	// 3.3 获取对象的值
	// get(Object object)
	System.out.println(name.get(o));

在这里插入图片描述

5.2、获取私有的成员变量age并使用

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的属性Field对象
	Field age = studentClass.getDeclaredField("age");
	
	// 3.1 准备一个学生对象
	Object o = studentClass.newInstance();
	
	// 暴力反写(因为age属性权限修饰符为private,故少了此行代码,程序会报非法访问异常:IllegalAccessException)
	age.setAccessible(true);
	
	// 3.2 为成员变量赋值
	// void set(Object 所属类的对象, Object 要赋的值)
	age.set(o, 30);
	
	// 3.3 获取对象的值
	// get(Object object)
	System.out.println(age.get(o));

在这里插入图片描述

小结

公共和私有变量获取使用的区别有以下两点:

获取方法不同:公共变量获取方法是getField();私有变量获取方法是getDeclaredField()

访问方式不同:公共变量访问不需要暴力破解;私有变量需要加一行代码(变量名.setAccessible(true); )

六、通过Class对象获取Method成员方法对象

我在Student类中添加了四个方法,两个私有,两个公开

public class Student {
    // 将name的修饰符设置为public
    public String name;
    private int age;
    private String sex;

    public Student() {
    }

    public Student(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    private Student(String name, int age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    // 添加以下四个方法
    private void add(){
        System.out.println("add.......");
    }

    private void delete(int id){
        System.out.println("delete.......");
    }

    public void update(){
        System.out.println("update.......");
    }

    public void find(int id){
        System.out.println("find.......");
    }

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

6.1、getMethods() 获取所有公共的成员方法

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
	Method[] methods = studentClass.getMethods();
	
	System.out.println("--------------Student对象的所有公共的成员方法对象如下--------------");
	for (Method method : methods) {
	    System.out.println(method);
	}

需要注意的是,这里包括了继承自Object类的一些公共方法 在这里插入图片描述

6.2、getDeclaredMethods() 获取所有的成员方法

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
	Method[] methods = studentClass.getDeclaredMethods();
	
	System.out.println("--------------Student对象的所有成员方法对象如下--------------");
	for (Method method : methods) {
	    System.out.println(method);
	}

需要注意的是,这里不包含继承自Object类的方法,是Student类中的所有成员方法(含私有的) 在这里插入图片描述

6.3、getMethod(String methodName, Class... args) 获取指定的某个公共的成员方法

值得一提,没有参数的方法可以获取,getMethod()方法的参数二空着就行

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
	Method method = studentClass.getMethod("find", int.class);
	
	System.out.println("--------------Student对象的指定名称和参数的公共的方法对象如下--------------");
	System.out.println(method);

在这里插入图片描述

6.4、getDeclaredMethod(String methodName, Class... args):获取指定的某个私有的成员方法

当然,这种方式也可获取到非私有方法对象

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
	Method method = studentClass.getDeclaredMethod("delete", int.class);
	
	System.out.println("--------------Student对象的指定名称和参数的私有的方法对象如下--------------");
	System.out.println(method);

在这里插入图片描述

小结

getMethods():获取所有公共的成员方法,包含了继承自Object类的方法

getDeclaredMethods():获取所有的成员方法,不包含继承自Objcet类的方法,是类的成员方法(私有+公共的)

getMethod(String methodName, Class... args):获取指定的某个公共的成员方法,只能是公共的

getDeclaredMethod(String methodName, Class... args):获取指定的某个私有的成员方法,私有&公共都可以

七、使用获取到的Method对象反射调用成员方法

使用invoke()方法调用成员方法,需要注意两点: (1)私有成员,使用前需要暴力破解,否则会报非法访问异常:IllegalAccessException; (2)反射调用成员方法前,需要先准备一个当前类的对象

	// 1.获取当前类(Student)的Class对象
	Class studentClass = Class.forName("com.essay.Student");
	
	// 2.通过当前类(Student)的Class对象获取当前类(Student)的某个方法对象
	Method method = studentClass.getDeclaredMethod("delete", int.class);
	
	// 3.通过当前类(Student)的方法Method对象的invoke方法调用方法
	
	// 私有成员,使用前需要暴力反射,否则报错非法访问异常:IllegalAccessException
	method.setAccessible(true);
	
	// 3.1 准备一个当前类(Student)的对象
	Object o = studentClass.newInstance();
	
	// 3.2 反射调用成员方法
	method.invoke(o, 10);

在这里插入图片描述

总结

程序执行过程中会有许多运行时异常,需要抛出,建议在方法上直接抛出 Exception 在这里插入图片描述

首次发布

hezhongying.blog.csdn.net/article/det…