Java中什么是反射,反射的用法

反射是啥?

反射既然有“反”,就说明它是一个逆向的过程。那我们先来看看正向过程是怎样的。

首先写一个实体类,new出该类的对象,然后调用属性、方法实现一些功能。
//没有反射时,new对象以及调用对象的属性以及方法

// An highlighted block
public void Test1(){
	//实例化对象
	Person person=new Person();
	//调用属性
	person.setAge(18);
	//调用方法
	person.show();
}

以上是我们不使用反射时创建对象,运用对象的用法,那到底什么是反射呢?反射的用法是啥?
Java程序的执行过程
我们可以看到,之前我们所运行的程序都是在编译时就已经链接了所有所需的类,也就是说程序运行的时候,项目所需要的类都已经加载好了,而反射则不是这样,它允许程序在运行的时候再加载、探知、使用那些在编译时未知的类,它是逆着来的。大概也可以这样理解,就是在程序加载运行的时候,同时再加载、使用一些未知的类,这两个操作是同时运行的。加载这些未知的类时,也可以通过一些方法得到这些类的相关信息

类比一个现实生活中的例子
1,姐妹,你见我的修眉刀没?
2,我昨天放粉饼的时候,好像在化妆桌的小抽屉里看到了,你去找找看看吧
3,好的

然后你从“粉饼”推出了“化妆桌的小抽屉”,然后找到了“修眉刀”
其实我们的反射也是这样的,在不知道类信息的时候,从类或者对象中推导出Class类型,然后再从Class中获取类的一些相关信息

这样我们也就知道了,要想拿到类的相关信息,第一步就需要先拿到Class类。

先说说什么是Class类

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。也就是说Class类是以上这些数据类型的类,也可以理解为是他们的“爷爷”
假如现在有一个Person类,Person类的实例对象是person,现在要通过Person类或者实例person拿到Class,然后再通过Class获取Person类的一些相关信息,比如方法名,修饰符、属性、方法、构造函数等等

反射的使用过程

          找到化妆桌小抽屉------获取Class类

知道了什么是Class类之后,我们就来说说怎么才能获取Class类

获取Class类有3种方式:

// An highlighted block
//获取person的Class类型,每个类型都有一个Class类型
        //方式一,知道类的实例时,用实例获取
        Person person = new Person();
        Class c1=person.getClass();
        //方式二,不知道实例时,用类名称获取
        Class c2=Person.class;
        //方式三,没有类名,也没有实例名,用Class的forname()方法获取
        Class c3;

        {
            try {
                c3 = Class.forName("cn.entity.Person");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        System.out.println(c1.hashCode());//通过打印他们的hashcode值来判断拿到的Class是不是同一个
        System.out.println(c2.hashCode());
        System.out.println(c2.hashCode());

这样就可以获取到Person的Class类了,现在已知条件有:Person类,Class类,以及c1。
在这里想说一下,c1、c2、c3叫做Person的“类类型”

          找到修眉刀------获取Person类的相关信息

应用一:获取Person类的基本信息
在这里插入图片描述

//获取person的Class类型,每个类型都有一个Class类型
        //方式一,用实例获取
        Person person = new Person();
        Class c1=person.getClass();
        System.out.println("名称是:"+c1.getName());
        System.out.println("简称是:"+c1.getSimpleName());
        System.out.println("修饰符是:"+c1.getModifiers());
        System.out.println("所包含的所有内部类:"+c1.getDeclaredClasses());
        System.out.println("所在的外部类:"+c1.getDeclaringClass());

运行之后的结果:
在这里插入图片描述
应用二:获取Person类的属性
在这里插入图片描述

//先获取Class类型
        Person person=new Person();
        Class c1=person.getClass();//类类型
        //使用getField()方法,只能访问修饰符为public
        System.out.println("---------getField()-----------");
        Field name=c1.getField("message");
        int modifiers = name.getModifiers();
        System.out.println("名字是:"+name.getName());
        System.out.println("类型是:"+name.getType());
        System.out.println("访问修饰符:"+ Modifier.toString(modifiers));

        //使用getFields()方法,只能访问修饰符为public
        System.out.println("---------getFields()-----------");
        for (Field field : c1.getFields()) {
            System.out.println("名字是:"+field.getName());
            System.out.println("类型是:"+field.getType());
            int m=field.getModifiers();
            System.out.println("访问修饰符:"+ Modifier.toString(m));
        }

        //使用getDeclaredFields()方法,不限制访问修饰权限
        System.out.println("---------getDeclaredFields()-----------");
        for (Field d : c1.getDeclaredFields()) {
            System.out.println("名字是:"+d.getName());
            System.out.println("类型是:"+d.getType());
            int m=d.getModifiers();
            System.out.println("访问修饰符:"+ Modifier.toString(m));
        }

运行之后的结果:
在这里插入图片描述
应用三:获取Person类的方法
在这里插入图片描述

System.out.println("=========方法展示=========");
        //获取Class类类型
        Class c1= Person.class;
        for (Method m : c1.getDeclaredMethods()) {
            System.out.println("方法名:"+m.getName());
            System.out.println("返回值类型是:"+m.getReturnType());
            Class[] types = m.getParameterTypes();
            System.out.print("该方法");
            if(types.length==0){
                System.out.println("没有参数列表");
            }else{
                for (Class c:types) {
                    System.out.print("的参数列表是:"+c.getSimpleName());
                }
            }
            int xiu=m.getModifiers();
            System.out.println("修饰符是:"+ Modifier.toString(xiu));
            //获取方法所属的类
            Class shi=m.getDeclaringClass();
            System.out.println("方法声明在:"+shi.getName()+"中");
            for (Class e : m.getExceptionTypes()) {
                if(e!=null){
                    System.out.print("该方法抛出的异常有:");
                    System.out.println(e.getName()+",");
                }

            }
            System.out.println("");
        }

运行之后的结果:
在这里插入图片描述
应用四:获取Person类的构造方法
在这里插入图片描述

System.out.println("============构造方法展示============");
        Class c1=Class.forName("cn.entity.Person");
        Constructor[] cs=c1.getDeclaredConstructors();
        for(int i=0;i<cs.length;i++){
            int xiu=cs[i].getModifiers();
            System.out.println("访问修饰符:"+ Modifier.toString(xiu));
            Class[] params=cs[i].getParameterTypes();
            if(params.length==0){
                System.out.println("该方法没有参数");
            }else{
                System.out.print("该方法的参数列表为:");
                for (Class p:params) {
                    System.out.print(p.getSimpleName()+"\t");
                }
            }
            System.out.println();
            System.out.println("-----------------------");
        }

运行之后的结果:
在这里插入图片描述
以上只是对个别功能的列举,更具体的可以去API文档中寻找:点击查看API
好了,最后我们再总结一下反射的概念:
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取、调用对象方法的功能称为java语言的反射机制。

反射存在的必要性?

“反射机制是很多java框架的基石”。(暂时我也不是很懂,只是看一些资料是这么说的)
(1)在xml文件或者properties里面写好了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射机制,根据这个字符串获得某个类的Class实例,这样就可以动态配置一些东西,不用每一次都要在代码里面去new或者做其他的事情,以后要改的话直接改配置文件,代码维护起来就很方便了。
(2)有时候要适应某些需求,Java类里面不一定能直接调用另外的方法,这时候也可以通过反射机制来实现。

反射的缺点

我们在代码中也能看到,反射的代码比正常调用的代码更多,性能也慢,所以应避免使用反射。这就相当于如果你本来就知道修眉刀在哪,就没必要再通过粉饼——化妆桌小抽屉——修眉刀这条路了。

是否使用反射的标准是啥?

如果一个功能可以不用反射完成,那么最好就不用。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

梦梦~~

你的鼓励是对我最大的动力

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

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

打赏作者

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

抵扣说明:

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

余额充值