Skip to content

反射

定义

20be19c2d8bc202b92d232f2492792dc_MD5 比如,IDEA自动补全,怎么知道某个对象有哪些方法的?答案是利用反射. 如果没有反射,想要从某个源文件获得类的成员信息,那么就需要一些类似于静态分析的方法.


获取class对象

e04b09c36c5ba3df86c4f41b0fed02e8_MD5 其中第一种方式是从class/源代码文件中获得的. 第二种是加载到内存时获得的 第三种是运行时获得的

示例

074d278115780de2136892ab2bfe698b_MD5 第一种最常用 第二种往往当参数使用.如synchronize中传递锁对象的代码. 第三种只有当我们有这个类的对象时才可以使用.


获取构造方法对象Constructor

372a7189ecc8dad825d2769b91c5e7d9_MD5

示例

0f8f85c48c68957aaf36d5f513d16c00_MD5 874863f169e1749cfad5f3ff1ee3335c_MD5

剖析

获得权限修饰符

返回的是一个int. a46b0a9aaa8da645b2ba0ca66706a0c5_MD5 df220965538c5b9f44e4ea6ae88fe035_MD5 因此,public返回的是1

获得参数

92ad8d58c5103ce0efd5bfb555f2da29_MD5

创建对象

8a655e54229b1904594a7748a58a82c7_MD5 但是,如果这个构造是私有的,那么会抛异常.因此,如果想要调用私有的: 1c9747466007a87ffc0a04947a393e1f_MD5 这种方式叫做暴力反射


获得成员变量对象Field

cb6a1f7d4d62c5262463ca7ef0ff6e58_MD5

获取所有成员变量

91fe8ceaf38a54ded6f90e7123ff55e0_MD5

获取单个成员变量

38d3b099809f583b671259df86589996_MD5

获取/修改的成员变量的值.

获取成员变量的名字,修饰符这些都不需要对象.但是获取值是需要的. 49714445a00578a7d052bfcbefed2e7c_MD5 注意,需要先获得field对象,从该对象的.get方法获得值. 注意,如果是私有的,那么要setaccessible. 修改也是同理的: 9fadcad8010a1cb672ac0182fb222511_MD5


获取成员的方法Method

98ed074e2dbc6ebb5b6aa15fd5c22220_MD5

示例

7f656dcabb064f1fd703fb53ebfa5c3c_MD5 注意,还得设置visiable 9ddfb66eb36e649c4c568564f9b8c5b2_MD5 还能获取异常 9147fc19a9ea06fab2fab9db5c753ee4_MD5 还能invoke(这个重要) e26a0bb8a794f2d55109d65f946d63ae_MD5


反射的作用

ed59e537e6ef3561630973d23dcefeb8_MD5

保存对象

678ef4ea0f560480158c8f6e03371950_MD5

配置文件+动态创建对象

211b8d86aaf8f0120778729979115278_MD5 c9c5aa401ce4119bf15d6516923921d8_MD5 这是配置文件: 4ec868d8ae34e95e01e9042f310836ac_MD5


动态代理

如果要给一段已经写好的代码修改,这是侵入式的,会很危险.因此,我们可以使用代理. 代理是非侵入式的,是可以给已有的代码添加功能的. 89362c64060a33ce19b34db2901b31ff_MD5 对象有什么方法想被代理,那么就需要代理有对应的方法. 那么有哪些方法需要被代理呢?我们可以把所有需要代理的方法写到接口里. 代理类和原先的类都需要实现中间的接口. 614b2a88683261a813f97b662c8e99e6_MD5

代码示例

原本的:

896bff5512a6d846e693dcfcb3152706_MD5 a4733fa8b3f69a198bd504833fedc85a_MD5 写成重写的: 484f4659777e93b0d0c6fd5b31ca13f2_MD5

代理之后

b97dacf344566c17c9ca1d5e3a01ee91_MD5 1bba1b1471a8903cd24fe00cde75d453_MD5 第一个参数:谁帮我们加载当前类的,就让它来加载.这个格式一般是固定的. 第二个参数:代理可以代理哪些接口.我们目前只有一个,因此放一个就行. c3dfad4531a20dffea2801ceb97298bb_MD5 我们希望这样调用: b629598f184b3eecfa6bed6d582ef87b_MD5 22eb340995302c99fe33fe94b511344d_MD5 这里的参数1一般不用. 2f23864347890105282fe85f758da9b2_MD5

执行过程: 调用sing方法时,会自动调用我们之前注册的invoke方法.我们只关注后面两个参数.其中mothod的参数对应的就是sing方法,因此就执行if分支.