博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
谈一谈Java中的反射机制
阅读量:7170 次
发布时间:2019-06-29

本文共 2630 字,大约阅读时间需要 8 分钟。

什么是反射?

JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

简单来说就是反射就是将 Java 类中的各种成分映射成一个个的 Java 对象。

在我们了解了反射的基本概念之后,自然而然的我们就提出了以下问题,反射有什么用?

假如有两个程序员,一个程序员在写程序的时需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码是不能通过编译的。此时,利用 Java 反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。

Java 的反射机制它知道类的基本结构,这种对 Java 类结构探知的能力,我们称为Java 类的“自审”。例如 一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。在 Java 中万物皆是对象,反射也是面向对象思想的一种体现。

说了这么多,感觉 好像还是云里雾里。那接下来就开始 show code。

首先 我们来创建一个 Robot 类。

public class Robot {    private String name;    public void sayHi(String helloSentence) {        System.out.println(helloSentence + " " + name);    }    private String throwHello(String tag) {        return "Hello " + tag;    }}复制代码

如代码所示,我们定义了一个私有的成员变量以及两个方法。

接下来我们就通过反射来获取它。

public class ReflectSample {    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {        Class rc = Class.forName("com.interview.javabasic.reflect.Robot");        Robot r = (Robot) rc.newInstance();        System.out.println("Class name is " + rc.getName());        Method getHello = rc.getDeclaredMethod("throwHello", String.class);        getHello.setAccessible(true);        Object str = getHello.invoke(r, "Bob");        System.out.println("getHello result is " + str);        Method sayHi = rc.getMethod("sayHi", String.class);        sayHi.invoke(r, "Welcome");        Field name = rc.getDeclaredField("name");        name.setAccessible(true);        name.set(r, "Alice");        sayHi.invoke(r, "Welcome");    }}复制代码

首先我们创建一个 Class对象 rc,并且通过 forName方法来给它赋值。这里我先给你提一个小问题,loadClass 和 forName 的区别,你可以先思考一下,答案会在文末给出。

接着我们的例子,我们通过 newInstance() 方法来创造一个实例,并且其强转为Robot对象。 紧接着我们输出 rc 的 name,rc 是通过我们传递的路径得到的,所以 name 自然是我们希望创建的 Robot 类。

我们通过 rc.getDeclaredMethod()方法得到了一个method对象,方法的参数对应着我们希望得到方法的名称。由于该方法是私有方法,所以我们 将 setAccessible() 设为true,表示反射在应用的时候,不会去进行权限检查。

由于 throwHello方法需要参数,我们就传入了Bob,最后输出的结果是 getHello result is Hello Bob

通过上述的代码,我们得到了 Robot对象以及它的方法,算是初步对反射有了一定的应用(后半部分的代码属于换汤不换药,就不再赘述)。

最后,我们来解答文中的问题 loadClass和forName有什么区别?

它们的区别就是 Class.forName得到的class是已经完成初始化完成的,Classloder.loadClass得到的class是还没有链接的。

简单来说就是 forName方法会执行类中静态代码块中的内容,而 loadClass不会执行,我们举一个简单的例子。

以 Class.forName("com.mysql.jdbc.Driver") 为例; Driver 类中有需要执行静态代码块(new Driver) 所以要用forname 不能loadclass。而springIoc 在读取bean的配置的时候 采取的是lazyloading(延时加载)的策略,使用 classloader 不需要执行静态代码块可以加快初始化速度,把相关加载留到真正执行代码的时候再操作。所以说这两种方法各有优劣,需要根据实际情况而定。

在本文中我们讲到了 Java 反射的相关内容,希望你看完本文后有所收获。

转载于:https://juejin.im/post/5cfe53765188254fb97442b8

你可能感兴趣的文章
投了10亿元发展“影游IP”的阿里游戏:不止于游戏分发
查看>>
WEB测试资料
查看>>
浅谈C#托管程序中的资源释放问题
查看>>
关于用VS实现开机自启动功能(win7/winXp)
查看>>
zz装完UBUNTU后要干的事
查看>>
Linux IPC实践(5) --System V消息队列(2)
查看>>
设置电脑间指定用户共享
查看>>
一种测试方向的探讨-基于模型测试调研引发的思考 - 3
查看>>
tinyPng Photoshop Plugin 安装的坑
查看>>
自动生成卡密SQL脚本(转载)
查看>>
【Android 开发入门】Android设备监视器之调试工具DDMS使用初探
查看>>
JS控制光标定位,定位到文本的某个位置
查看>>
2016年IoT和新的逃逸技术引领威胁态势
查看>>
《敏捷软件开发:原则、模式与实践(C#版.修订版)》—第1章1.2节 原则
查看>>
PHP7扩展开发之类型处理
查看>>
git教程(三)--创建项目并提交更新
查看>>
【推荐】可视化代码评审工具 Phabricator - 我看过的PHP开源框架
查看>>
jQuery.extend 函数详解
查看>>
磁盘管理
查看>>
我的友情链接
查看>>