关于java反射的学习。

抽象概念确实不好懂,每个人都可能对反射有自己的理解。

建议先看知乎建议初步印象:https://www.zhihu.com/question/24304289

一、概念

java反射机制是:

  1. 运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法。
  2. 对于任意一个对象,都能够调用它的任意一个方法和属性。

这种动态获取的信息以及动态调用对象的方法的功能,称为java语言的反射机制。

要让java程序能够运行,那么就得让java类被虚拟机加载(java类如果不被java虚拟机加载,是不能正常运行的)。现在我们运行的所有的程序,在编译期的时候就已经知道:“你需要的那个类已经被加载了”。

如果使用反射,那么在编译期间,虚拟机并不能确定是哪个类被加载了,只有在程序运行的时候才加载、探知、自审、使用在编译期并不知道的类。这就是反射的特点。

Java反射机制的实现要借助于4个类:

  1. Class
  2. Constructor
  3. Field
  4. Method

其中:

  1. Class代表的是类对象。
  2. Constructor是类的构造器对象。
  3. Field是类的属性对象。
  4. Method是类的方法对象。

通过这四个对象我们可以粗略的看到一个类的各个组成部分。

二、存在的意义

参考:https://www.zhihu.com/question/28570203

这个问题下的回答都讲得很好,我理解的不如他们精辟。所以我只是摘选一些语录,帮助理解反射的意义。

“反射其实是通过允许在运行时存取程序数据,以改变程序行为的程序设计技术。”

“静态编译型语言需要一些动态能力;需要把一些在编译时必须要做的事情推迟到运行时来做,而这种能力可以给编译型语言赋予强大的灵活性。”

“没有反射,给你个对象,让你把这个对象的所有方法和属性列出来,你怎么办?”

“反射有它独到的能力,获取对象“元数据”的能力,即获取描述对象、关于对象的数据的能力,无可替代。没错,反射确实破坏了封装,但这是一种权衡。所以能不用反射尽量别用。”

说到这里,我想补充个例子:

我平时的工作流程就像静态编译型语言一样,做什么已经有一套规范了(已经被编译好了),这套规范是老板制定的,我按照去做就可以了,不能轻易改变。

突然有一天,老板想要叫我来办公室一趟,于是给我发了一条短信,我当然得根据老板的指示去做。这里的“短信”就是一个突发情况,改变了我的工作流程。

在这个例子中,我们可以把“老板发送短信的能力”称为反射。有了反射,老板可以灵活地指挥我的工作(使用反射调控程序),而不必重新制定一套工作规范(改写静态程序,重新编译)。

三、一些具体作用

用几个场景进行说明:

(1)动态获取类

假如有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?

当然不能,类都不存在,怎么能编译过关。

但是,如果利用java反射去获取类,就可以跳过编译器的检查,让第一个程序员在没有得到第二个程序员所写的类的时候,完成自身代码的编译。

(2)自省

java的反射机制知道类的基本结构,这种对java类结构探知的能力,称为java类的“自审”。

使用eclipse的时候,往往会使用到自动补全功能,编译工具会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了java反射的原理,是对创建对象的探知、自审。

(3)灵活性

举个例子:

通过反射和配置文件的配合,可以在不重新编译程序的情况下更换执行的方法,让程序更灵活。

这就是“在静态程序执行时依然能够改变其行为”。

四、反射实例

简单的实例:

(1)所有的java类都继承自Class类

如果需要使用到反射,第一件事就是获取类的class。

有如下几种方法:

  1. String str = “myclass”; Class class = str.getClass();
  2. Class class = myclass.getClass();
  3. Class s = myclass.getSuperclass();

(myclass是一个类)

(2)获得Class类之后,如果需要使用Class中方法,先要取得Method

首先要使用class的getMethod方法获得method对象,需要填入函数名和函数的参数类型

  1. Method m1 = class.getMethod(“print”, new Class[] { int.class, int.class });
  2. Method m2 = class.getMethod(“print”, String.class, String.class);

如果不匹配,就会报错

Method m3 = c.getMethod(“print”, int.class, String.class); // 这里应该都是int

m3.invoke(test, new Object[] { 1, 2 });

运行报错:java.lang.NoSuchMethodException: com.xie.reflect.test.print(int, java.lang.String)

(3)method填入参数进行使用

  1. m1.invoke(test, new Object[] { 1, 2 });
  2. m2.invoke(test, “xie”, “yxin”);

需要填入的是方法所在类,和方法的参数,参数可以用数组,也可分开填写。

(补充一下,这里的反射可以绕过编译时的参数检查,但是具体有什么用,我就不知道了…)

结果为:

可以看见,虽然syso列表没问题,但是一旦需要遍历,就会报错。现实开发中不要这样使用。

五、总结

我的个人理解:反射给了静态语言动态能力。

反射是各种java框架都广泛运用的技术,要深入理解框架,必须先学好反射机制。

1 对 “java 反射”的想法;

发表评论

电子邮件地址不会被公开。 必填项已用*标注