反射机制及其使用方法(下)

在这里插入图片描述

反射的使用方法

在这里插入图片描述
在我们了解了反射机制后,我们知道Class对象是反射机制的关键,下面介绍的反射的使用方法同样是Class类为重点。
为方便阅读,我将上篇最重要的三阶段图也放在这篇里。
在这里插入图片描述

获取类所对应的Class对象的三种方法

  1. 使用Class类中的静态方法forName()

    使用这种方式获取Class对象,需要明确该类的全限定名
    多用与结合配置文件的使用,通过在配置文件里利用键值对等方法来编写全类名
    程序读取文件,得到全类名,来得到Class对象
    简单点就是从properties文件提取类名方式使用

    这个方法对应着源代码阶段

    // budiu包下的Dog类所对应的Class对象
    Class cls=Class.forName("budiu.Dog");
    
  2. 调用类的静态变量class

    在有重名的类时,一定要检查清楚自己引用的类是正确的
    多用于参数传递,类似于继承等使用

    这个方法对应类加载器阶段

    Class cls1=Dog.class;
    
  3. 调用对象的getClass()方法

    这个方法是你编写类时默认就有的(Object类里面的方法),不用自己写,类似于toString方法,你没编写它也会有一个默认的
    多用于获取对象的字节码形式,将类名放入porperties等类型的文件

    这个方法对应运行时阶段

     //调用对象方法来获取
     Dog dog=new Dog();
     Class cls2=dog.getClass();
    

注意

在程序运行时,同一个类只会被加载一次,也就是只生成一个对应的Class对象。假如说我前面的三种获取Class对象方式都是在一个程序中所获取,那么cls,cls1,cls2的地址也会相同。

利用Class对象可实现的一些操作

上面已经说到我们常用的操作主要就是与成员变量、构造器方法、成员方法有关,还有一个获取类名称也较为常用,其他的可以暂时不深究。

在这里插入图片描述

为方便举例,我们仍使用上面所创建的Dog类:

package budiu;/*Author:l
Explain:
Version:1.0*/

public class Dog {
    //属性
    public String name;
    private int age;
    //公共构造器
    public Dog(){}
    public Dog(int age){
        this.age=age;
    }
    //私有构造器
    private Dog(String name){
        this.name=name;
    }

    //get和set方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }


    //方法
    //公共方法
    public void play(){
        System.out.println("捡球");
    }
    private void sleep(){
        System.out.println("睡觉");
    }
}

获取类名

getName() 方法:返回类的名称。它可以在需要获取类名时使用,例如在日志记录或调试过程中。
其实本人认为toString方法是相同的效果,但它存在肯定是有它的道理的

Class cls=Class.forName("budiu.Dog");
String cls_name=cls.getName();
System.out.println(cls_name);

获取成员变量(Fields [])

getField() 方法:需要在括号里传入你要获取的成员变量名,返回对应的成员变量的Field对象,只能获得公共成员变量
getDeclaredField()方法:需要在括号里传入你要获取的成员变量名,返回对应的成员变量的Field对象,可以所有成员变量,不受访问权限修饰符影响

getField()方法:返回所有成员变量的Field对象数组,但不包括私有(private修饰)成员变量
getDeclaredFields() 方法:返回所有成员变量的Field对象数组,包括私有(private修饰)成员变量

//常用的获取成员属性的四种方法
        Field[] fields=cls.getFields();
        Field[] declaredFields=cls.getDeclaredFields();
        Field field1=cls.getField("name");
        Field field2=cls.getDeclaredField("age");

Field对象的使用

获取到的Field对象可以用来获取和设置对应成员变量的值。如果获取的Field对应的成员变量是私有的,通常情况下是不能直接使用的,因为我们只是获取到到了它的Field对象而已,私有成员变量只能在它们所属的类内部访问。

Class cls=Class.forName("budiu.Dog");
        String cls_name=cls.getName();
        System.out.println(cls_name);


        //常用的获取成员属性的四种方法
        Field[] fields=cls.getFields();
        Field[] declaredFields=cls.getDeclaredFields();
        Field field1=cls.getField("name");
        Field field2=cls.getDeclaredField("age");
      	//创建一个实例化对象
        Dog dog=new Dog();
        
        //原有的age属性是私有的
        //要用这个方法去无视访问权限
        field2.setAccessible(true);
        //将Dog类的实例化对象dog的私有属性age设置值和获取值
        field2.set(dog,15);
        field2.get(dog);

然而,通过反射机制,我们可以绕过访问权限限制来访问私有成员变量。在使用反射访问私有成员变量时,需要调用Field对象的setAccessible(true)方法,以允许访问私有字段。然后,可以使用Field对象的get()方法来获取私有成员变量的值,或使用set()方法来设置私有成员变量的值。

获取构造器

getConstructor()该方法用于获取当前Class所表示类的public修饰的构造器。
getDeclaredConstructor()该方法用于获取当前Class所表示类的public修饰的构造器。

你需要通过在括号里传入参数类型来获取指定构造器,没有就是获取无参构造器。

getConstructors(): 该方法用于获取当前Class所表示类的public修饰的构造器。
getDeclaredConstructors(): 该方法用于获取当前Class所表示类的所有构造器,无视访问权限。

//四种获取构造器的方法
Constructor constructor=cls.getConstructor();
Constructor declaredConstructor=cls.getDeclaredConstructor();
Constructor[] constructors=cls.getConstructors();
Constructor[] declaredConstructors=cls.getDeclaredConstructors();

构造器的使用

为避免篇幅过长,这里只举私有构造器的使用
只需要利用newInstance()方法和setAccessible()方法即可。

//只举私有构造器的使用
        //私有构造器
//            private Dog(String name){
//                    this.name=name;
//                }
        //这里我不想遍历里面的构造器数组,直接用构造器传参特征来获取对应构造器
        Constructor privateConstructor=cls.getDeclaredConstructor(String.class);
        privateConstructor.setAccessible(true);
        
        //利用newInstance即可构造并创建对象
        Dog reflect_dog=(Dog) privateConstructor.newInstance("来福");

Method对象的获取

getMethod()方法: 这个方法用于获取公共的方法。
getDeclaredMethod()方法: 这个方法用于获取所有的方法,无论公共的还是非公共的。

getMethods()方法:用于获取某个类的所有公共方法。
getDeclaredMethods()方法:获取某个类的所有声明的方法。

//四种获取Method对象的方法
Method method=cls.getMethod("setName", String.class);
Method declaredMethod=cls.getDeclaredMethod("sleep");
Method[] methods=cls.getMethods();
Method[] declaredMethods=cls.getDeclaredMethods();

Method的使用

只要了解invoke()和setAccessible()方法即可,
这里以sleep()方法的执行为例

//私有方法原型
//        private void sleep(){
//            System.out.println("睡觉");
//        }
        
        //sleep方法的使用
        declaredMethod.setAccessible(true);
        declaredMethod.invoke(dog);

    }

总结

在学习初阶编程的时候,我们并不会频繁的使用反射,它虽然有着许多有点,但对于我们新手而言,代码复杂度也会一定程度上攀升。所以重点的是了解它的原理,这会为我们以后的框架学习带来更多感悟,记得老师曾经说过,反射机制是框架的灵魂所在。

顺便便把我做笔记的源码放在这,和上方的Dog类一起即可运行,注意全类名要改成自己的,包名应该用自己的包名。

package budiu;

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

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException {
        Class cls=Class.forName("budiu.Dog");//注意改成自己的包名
        String cls_name=cls.getName();
       


        //常用的获取成员属性的四种方法
        Field[] fields=cls.getFields();
        Field[] declaredFields=cls.getDeclaredFields();
        Field field1=cls.getField("name");
        Field field2=cls.getDeclaredField("age");


        Dog dog=new Dog();


        //原有的age属性是私有的
        //这个必须得有
        field2.setAccessible(true);
        //将Dog类的实例化对象dog的私有属性age设置值和获取值
        field2.set(dog,15);
        field2.get(dog);

        //四种获取构造器的方法
        Constructor constructor=cls.getConstructor();
        Constructor declaredConstructor=cls.getDeclaredConstructor();
        Constructor[] constructors=cls.getConstructors();
        Constructor[] declaredConstructors=cls.getDeclaredConstructors();


        //只举私有构造器的使用
        //私有构造器
//            private Dog(String name){
//                    this.name=name;
//                }
        //这里我不想遍历里面的构造器数组,直接用构造器传参特征来获取对应构造器
        Constructor privateConstructor=cls.getDeclaredConstructor(String.class);
        privateConstructor.setAccessible(true);

        //利用newInstance即可构造并创建对象
        Dog reflect_dog=(Dog) privateConstructor.newInstance("来福");


        //四种获取Method对象的方法
        Method method=cls.getMethod("setName", String.class);
        Method declaredMethod=cls.getDeclaredMethod("sleep");
        Method[] methods=cls.getMethods();
        Method[] declaredMethods=cls.getDeclaredMethods();

        //私有方法原型
//        private void sleep(){
//            System.out.println("睡觉");
//        }

        //sleep方法的使用
        declaredMethod.setAccessible(true);
        declaredMethod.invoke(dog);

    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗不丢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值