Java反射

反射是Java中的一个重要内容,反射可以实现Java在编码过程中的动态性,可以更加灵活编写代码,但是反射使用不当会造成很高的资源消耗。学习反射,可以更好理解Java面向对象的核心概念,不断深入和了解,真正理解“世间万物皆对象”

文章介绍

本文先回介绍Java在创建对象的一个基本过程,深入到底层,来引出发射的概念,探讨反射机制的具体实现和反射机制的效率,最后讲解如何提高反射机制的效率

创建对象基本过程

●Java代码在计算机中经历的三个阶段:如下图所示
Java代码在计算机中经历的三个阶段
上图解析:首先计算机CPU只会从内存中读取数据,不会从硬盘中读取数据。在Java代码写好之后,经过编译器进行编译,形成.class字节码文件,虚拟机使用类加载器(ClassLoader)将类从硬盘加载到内存当中,形成Class类对象(我到这里理解了原来一个类也可以看作一个对象)其中有成员变量,构造方法,还有成员方法等等,他会加载到内存中的一个方法堆区,最后到达运行阶段从方法堆区中读取类的信息。
●创建对象时的内存结构
创建对象的内存结构
当类加载到方法区中之后(这个就是类的模板,根据类的模板来创建对象,就像是一面镜子),在栈中创建对象的引用,在堆中创建user对象,将创建好的对象的地址赋给栈中对象的引用等

反射介绍

●概念:动态获取类的信息以及动态区调用对象方法,这就是反射机制(我理解的反射就是操作类对象,通过Class对象,来操作创建好的类,拿到这个类中的所有东西)
●Class这个对象就像一面镜子,透过这个镜子可以看到类的结构,所以,我们形象的称之为:反射。 因此,“Class 对象”是反射机制的核心

反射的具体实现

●获取Class对象的三种方式
通过GetClass()方法、通过.class静态属性、通过Class类中的静态方法forName()

Class cs=users.getClass();
Class cs=Users.class;
 Class cs=Class.forName("javareflect.Users");

类对象获取之后,我们就可以通过类对象来对操作某个类中的一些东西了,具体操作如下:(看完方法再看这一句话:总结以下,大同小异,只要方法中带”Declared“的,可以忽视私有,任意的都可以得到,而没有Declared的只可以获得公共的,有”s“的都是获得全部,不带s的都是获得具体的单个,)
●获取类的构造方法
获取类的构造方法

●获取类的成员变量
获取类的成员变量

●获取类的方法
获取类的方法
获取到类的方法之后,最重要的还是使用,用invoke()方法就可以
●获取类的一些其他信息
比如:获取类名,获取包名、获取超类(直接父类)、获取该类是实现的所有接口等等,和上面列举的大同小异,可以参照具体API文档进行学习,举一反三,这里就不一 一列举。

反射应用案例

应用说明:根据给定的方法名顺序来决定方法的执行顺序
先创建一个方法类

package javareflect;

public class ReflectTest {
    public void method1(){
        System.out.println("method1...");
    }
    public void method2(){
        System.out.println("method2...");
    }
    public void method3(){
        System.out.println("method3...");
    }
}

创建测试类

package javareflect;

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws Exception{
        ReflectTest rf=new ReflectTest();
        if (args!=null&args.length>0){
            //获取ReflectTest的Class对象
            Class c=ReflectTest.class;
            //通过反射获得ReflectTest下的所有方法
            Method[] methods=c.getMethods();
            //通过遍历来对主方法中参数和Methods数组中方法的匹配
            for (String str:args){
                for (int i=0;i<methods.length;i++){
                    if (str.equalsIgnoreCase(methods[i].getName())){
                        methods[i].invoke(rf);
                        break;
                    }
                }
            }
        }else {
            rf.method1();
            rf.method2();
            rf.method3();
        }
    }
}

在主方法中有个参数String类型的数组,名字叫args,如果我们不设置,他是空的,不传递参数,但是如果我们传递了参数,我们可以根据参数参数的顺序来决定方法执行的顺序
下图就是在主方法中传入参数:
在这里插入图片描述
运行截图
不在主方法中添加参数:
不传入参数

在主方法中传入参数:
传入参数

反射机制的效率

●由于 Java 反射是要解析字节码,将内存中的对象进行解析,包括了一些动态类型,而JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多!
●反射机制的效率测试
首先创建Users类

package javareflect;

public class Users {
    private  String name;
    public   int age;
    private  void method(){
        System.out.println("method");
    }
    public Users() {
    }

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

    public  Users(String name) {
        this.name = name;
    }

    private Users(int age) {
        this.age = age;
    }

    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;
    }
}

我们对Users类中的setAge方法进行一亿次的调用来感受,通过反射创建对象执行的效率和通过new创建对象执行的效率

package javareflect;

import java.lang.reflect.Method;

public class Test2 {
    public static void main(String[] args)throws Exception {
        //通过反射方式执行的效率
        Class c=Users.class;
        long Reflectstart=System.currentTimeMillis();
        Users user=(Users) c.newInstance();
        Method method=c.getMethod("setAge", int.class);
        for (int i=0;i<100000000;i++){
            method.invoke(user,18);
        }
        long Reflectend=System.currentTimeMillis();
        //通过普通方式执行的效率
        long start=System.currentTimeMillis();
        Users users=new Users();
        for (int i=0;i<100000000;i++){
            users.setAge(18);
        }
        long end=System.currentTimeMillis();
        System.out.println("使用反射的时间"+(Reflectend-Reflectstart));
        System.out.println("不使用反射的时间"+(end-start));
    }
}

运行结果
效果对比

提高反射机制的效率

●首先先介绍setAccessible()方法:setAccessible 是启用和禁用访问安全检查的开关。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检
查;默认值为 false。虽然之前我们可以获得类中的一些私有属性和方法,但是我们不可以操作他们,因为我们没有关闭访问性检查。
●如果我们在上一个效率测试的案例中加入忽略安全性检查,我们再看运行结果
关闭安全性检查

总结

●Java 反射机制使得 Java具有了动态性
●优点:更灵活,更开放
●缺点:降低了效率,增加了代码维护困难

以上就是我现阶段对Java反射机制的了解和所得,如果有理解不对的地方,还望大家多多指教,之后有更加深入的学习,我会及时的进行补充,希望我和大家一起共同进步!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值