Day2_Java进阶_Java反射【特别重要】

2020.7.6 10:37:00

一、反射概述

示例1:不同的人通过X光机得到类似的影像资料。在影像资料中包含人体的各个组成部分。

在这里插入图片描述

示例2:学生类Student和老师类Teacher要想使用需先通过类加载器加载为对应的.class文件到内存。在.class文件中包含了成员方法、构造方法、成员变量等等一些相似的信息。Class是所有的.class文件对象所对应的类型。也就是说是所有类的影像。

我们可直接通过Class类获取所有类的成员方法、构造方法等信息,而不是去找到Student类或其他类来得到这些信息。

在这里插入图片描述

Java反射机制:是指在运行时去获取一个类的变量和方法信息。然后通过获得到的信息来创建对象,调用方法的一种机制
由于这种动态性,可以极大的增加程序的灵活性,程序在不用在编译期就完成确定,在运行期仍然可以拓展。

二、反射获取Class类的对象的三种方式

我们要想通过反射去使用一个类,首先我们需要获取到该类的字节码文件的对象,也就是类型为Class类型的对象。

这里我们提供了三种方式来获取Class类的对象:

  1. 使用类的class属性来获取该类对应的Class对象
    举例:Student.class将会返回Student类对应的Class对象。
  2. 调用对象的getClass()方法来 返回该对象所属类对应的Class对象
    getClass() 方法是Object类中的方法,所有的Java对象都可以调用该方法。
  3. 使用Class类中的静态方法forName(String className),该方法需要传入字符串参数,该字符串参数的值为某个类的全路径,也就是完整包名的路径。
    示例:

①新建一个Student类:

package com.hoqis;

/**
 * @author HoQis
 * @create 2020-07-06 14:30
 */
public class Student {
    //成员变量:一个私有、一个默认、一个公共
    private String name;
    int age;
    public String address;

    //构造方法,一个私有、一个默认、两个公共
    public Student() {
    }

    private Student(String name){
        this.name=name;
    }

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

    public Student(String name, int age, String address){
        this.name = name;
        this.age = age;
        this.address = address;
    }

    //成员方法:一个私有、四个公共
    private void function(){
        System.out.println("function!!!");
    }

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

    public void method2(String s){
        System.out.println("method2"+s);
    }
    public String method3(String s,int i){
        return s+","+i;
    }

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

②新建一个获取Student类的ReflectDemo类。分别介绍了三种方式来获取Class类对象。

package com.hoqis;
/**
 * @author HoQis
 * @create 2020-07-06 11:25
*/

/*
三种方式来获取Class对象
    1.使用类的class属性来获取该类对应的Class对象
    2.调用对象的getClass()方法来获取所属类对应的Class对象
    3.使用Class类中的静态方法forName(String className),需传入字符串参数,该参数为某个类的全路径【完整包名】
 */
public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.使用类的class属性来获取该类对应的Class对象
        Class<Student> c1 = Student.class;
        System.out.println("使用类的class属性来获取该类对应的Class对象:"+c1);

        Class<Student> c2 = Student.class;
        System.out.println(c1==c2);
        System.out.println("---------------------------");
        
        //2.调用对象的getClass()方法来返回该对象所属类对应的Class对象
        Student student = new Student();
        Class<? extends Student> c3 = student.getClass();
        System.out.println(c1==c3);
        System.out.println("---------------------------");

        //3.使用Class类中的静态方法forName(String className)
        Class<?> c4 = Class.forName("com.hoqis.Student");
        System.out.println(c1==c4);
    }
}

控制台打印得到的结果为:

使用类的class属性来获取该类对应的Class对象:class com.hoqis.Student
true
---------------------------
true
---------------------------
true

Process finished with exit code 0

【总结】说明这三种方式都能够正常获取到该类对应的Class对象。

三、反射获取构造方法并使用

在这里插入图片描述

1.首先我们需要先去获取Class对象。

Class<?> c = Class.forName(“com.hoqis.student”);

2.有以下三种方式来获取该类的构造函数,分别为只获取公共的,所有的以及单个。

①使用getConstructors()方法来获取该Class对象表示的类的所有公共的构造函数。 【只能拿到公共的构造函数,其他的不能获取到】

Constructor<?>[] cons = c.getConstructors();//这里获取到是构造函数的数组,故需以下方法进行循环遍历出每一个构造函数
for(Constructor con : cons){
	System.out.println(con);
}

②使用getDeclaredConstructors()来获取所有的构造函数。【包含私有的和默认的以及公共的构造函数】

Constructor<?>[] cons = c.getDeclaredConstructors();//这里获取的是构造函数的数组,故需要以下进行循环遍历
for(Constructor con : cons){
	System.out.println(con);
}

③ 使用getConstructor()方法来获取一个Constructor对象。该方法提供了一个类的单个构造函数的信息和访问权限。

Constructor<?> con = c.getConstructor();
Object obj = con.newInstance()//使用这个newInstance()方法来创建该类的实例对象,相当于Student s = new Student();
System.out.println(obj);

2020.7.19 13:23:44

四、使用反射来实战操作

练习1.获取单个构造方法来访问类中的public公共方法,需知道public公共方法里的参数。

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

练习2:访问类中私有的方法,需使用暴力进行反射。

在这里插入图片描述
在这里插入图片描述
反射获取的结果如下:
在这里插入图片描述

五、使用反射来获取类中的成员变量并练习使用

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

1、使用getFields()方法来获取实体类中的公有的成员变量

在这里插入图片描述
反射获取成员变量输出结果如下图所示:
在这里插入图片描述

2、使用getDeclaredFields()方法来获取所有的成员变量

接下来我们需要对该Student实体类使用反射来获取到该类中的默认私有以及公有的成员变量。
只需调用getDeclaredFields()方法即可完成对所有的成员变量进行访问。
在这里插入图片描述
反射获取到的三个不同修饰符的成员变量的结果如下图所示:
在这里插入图片描述

3、获取到单个Field对象,并通过set(被赋值的对象,“值”)方法来对成员变量进行赋值操作

在这里插入图片描述
将address的值设置为‘西安’结果如下图所示:
在这里插入图片描述

六、反射获取成员变量并使用练习

在这里插入图片描述
访问私有的成员变量需要调用setAccessible()方法进行取消访问检查操作,不然系统会报非法异常。
在这里插入图片描述
2020.7.19 22:50:18

七、反射获取成员方法并使用

在这里插入图片描述

//1.获取Class对象
Class<?> c = Class.forName("com.hoqis.Student");

//2.获取类成员方法getMethods():返回一个包含方法对象的方法,类和接口的所有公共的方法,也包含继承父类的。
Method[] methods = c.getMethods();
for(Method method : methods){
	System.out.println(method);
}getDeclaredMethods():本类和接口所有声明的方法,不包含继承的方法。
Method[] methods = c.getDeclaredMethods();
for(Method method : methods){
	System.out.println(method);
}

//获取单个的方法对象
getMethod()  
getDeclaredMethod()

Method m = c.getMethod("method1");
//获取无参构造方法创建对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//在类或接口上提供有关单一方法的信息和访问权限 invoke
m.invoke(obj);

在这里插入图片描述

八、反射获取成员方法并使用练习

在这里插入图片描述

获取Class对象
Class<?> c = Class.forName("com.hoqis.Student");
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();

Method m1 = c.getMethod("method1");
m1.invoke(obj);

Method m2 = c.getMethod("method2",String.class);
m2.invoke(obj,"林青霞");

Method m3 = c.getMethod("method3",String.class,int.class);
Object o = m3.invoke(obj,"林青霞",30);
System.out.println(o);

//调用私有的方法时,需要使用暴力进行访问
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj)

得到的结果为:
在这里插入图片描述
2020.08.03 23:16:36

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值