0
点赞
收藏
分享

微信扫一扫

java中的反射总结


刚开始学习java的时候真的很难理解反射到底是个什么东西

一些书籍,哪怕是很经典的书籍都解释的让人感觉懵懵的,或许的确是我太笨

况且,网上说在将来学习框架的时候需要经常应用到反射机制,这样一来总让人心里有些不安

就方才偶然又把讲解反射的章节和视频看了一点,觉得能理解一些了

现在决定一鼓作气,边看边写,顺便把一些主要的内容和操作都记载到这里

我想,对于我这么一个笨笨的人来说,学习的最好方法也许就是不断重复

遇到不懂的知识就停下来把以往的重新学一遍,虽然浪费了很多时间,但对我也有些效果

 

我的理解是:所谓反射,就是根据一个已经实例化了的对象来还原类的完整信息

至少对我而言,我认为它带给我的好处是,让我从下往上的又了解了一遍面向对象

x_x 在此又痛恨一边那些厚部头们,把我的脑细胞搞死一片

 

Class类

如果要完成反射,那么必须了解Class类

实例1:通过对象取得包名和类名

​​package​​          ​​org.siu;​​        





​​class​​ ​​Test {​​





​​}​​





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) {​​


​​Test t = ​​ ​​new​​ ​​Test();​​


​​System.out.println(t.getClass());​​


​​System.out.println(t.getClass().getName());​​


​​}​​


​​}​​


编译结果如下,注意包的编译方式即可

此处的getClass()方法是默认继承自Object类的


java中的反射总结_反射类

 

在java中,Object类是所有类的父类,同样,所有类的实例化对象也都是Class类的实例

因此,这样一来就会牵扯到向上转型和向下转型的概念

由于向下转型的不安全因素,在这里泛型也会接踵而来

(不过我想说的是,此处的泛型设计很刺眼!尼玛,整个java的语法设计同样刺眼,超恶心!!!)

 

实例2:Class类的实例化

由于Class类没有构造方法,所以实例化Class类的方式有点特殊,有三种方式:

  • 对象.getClass( )
  • 类.Class
  • forName( )

​​class​​          ​​Test {​​        





​​}​​





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) {​​


​​//方式一:​​


​​Test t = ​​ ​​new​​ ​​Test();​​


​​Class<? ​​ ​​extends​​ ​​Test> c1 = t.getClass();​​


​​System.out.println(c1);​​





​​//方式二:​​


​​//为了避免特殊性,这里不用Test类,而用java库中的String类​​


​​Class<String> c2 = String.​​ ​​class​​ ​​;​​


​​System.out.println(c2);​​





​​//方式三:​​


​​//forName()方法会抛出异常​​


​​Class<?> c3 = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c3 = Class.forName(​​ ​​"Test"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​System.out.println(c3);​​


​​}​​


​​}​​


 其中,forName( )方法需要重点掌握,因为它可以在类不确定的情况下实例化Class,更具灵活性


java中的反射总结_构造方法_02

 

Class类的应用

Class类中有一个方法叫做newInstance( ),它可以用来创建一个Class类对象的新实例

怎么说呢?Class对象包含的内容就是反射好的那个类,我们要构造那个类的新实例(新对象)

实例3:Class类的无参构造对象

​​public​​          ​​class​​          ​​Demo {​​        


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) {​​


​​//实例化Class对象,forName()方法会抛异常​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​//这里需要完整的包名和类名​​


​​c = Class.forName(​​ ​​"java.lang.String"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​





​​//生成一个字符串的引用​​


​​String s = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​//将构造好的对象向下转型为String类​​


​​//newInstance()方法会抛异常​​


​​s = (String) c.newInstance();​​


​​} ​​ ​​catch​​ ​​(InstantiationException e) {​​


​​e.printStackTrace();​​


​​} ​​ ​​catch​​ ​​(IllegalAccessException e) {​​


​​e.printStackTrace();​​


​​}​​


​​System.out.println(​​ ​​"字符串长度: "​​ ​​+ s.length());​​


​​}​​


​​}​​


这样就通过无参数的形式构造了一个新的对象,如同正常模式中

通过无参构造方法来构造新对象一样


java中的反射总结_反射类_03

我们知道,类中除了有无参构造方法,还会存在有参数的构造方法

那在反射中如何通过有参数的形式构造对象呢?接着看

 

实例4:Class类的有参构造对象

​​import​​          ​​java.lang.reflect.Constructor;​​        





​​public​​ ​​class​​ ​​Demo {​​


​​//下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c = Class.forName(​​ ​​"java.lang.String"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​char​​ ​​[] ch = {​​ ​​'h'​​ ​​,​​ ​​'e'​​ ​​,​​ ​​'l'​​ ​​,​​ ​​'l'​​ ​​,​​ ​​'o'​​ ​​};​​


​​String s = ​​ ​​null​​ ​​;​​


​​//获得Class类对象的有参构造方法,括号里面参数的写法是:类型.class​​


​​Constructor<?> con = c.getConstructor(​​ ​​char​​ ​​[].​​ ​​class​​ ​​);​​


​​//用此构造方法构造一个新的字符串对象,参数为一个char数组​​


​​s = (String) con.newInstance(ch);​​


​​System.out.println(​​ ​​"构造的字符串:"​​ ​​+ s);​​


​​}​​


​​}​​


我们还是使用String类做例,因为String类用的比较多,便于理解

这里需要注意的是,构造方法需要使用getConstructor( )方法获得

至于参数类型则是:原有类型.class


java中的反射总结_System_04

还有一点,无论是有参还是无参,这里所使用的构造方法,原本的类里面必须对应存在

那么,如何才能知道原有类里面的构造方法,普通方法,继承的父类等详细信息呢?接着看

 

获取类的结构

要通过反射获取类的结构我们这里要导入一个新的包java.lang.reflect

实例5:取得类的构造方法

​​import​​          ​​java.lang.reflect.Constructor;​​        


​​import​​ ​​java.util.Arrays;​​





​​public​​ ​​class​​ ​​Demo {​​


​​//下面的几个方法抛出来的异常太多,为了代码的紧凑性,这里就直接抛给虚拟机了​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c = Class.forName(​​ ​​"java.lang.Boolean"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​//这里的getConstructors()方法返回的是一个Constructor数组​​


​​Constructor<?>[] cons = c.getConstructors();​​


​​//打印的方式你可以自己写,为了方便我用Arrays.toString(),凑合着看​​


​​System.out.println(Arrays.toString(cons));​​


​​}​​


​​}​​


 我选择了Boolean类来做例,因为Boolean类的构造方法就两个,方便看


java中的反射总结_构造方法_05

 

实例6:取得类所实现的接口

​​import​​          ​​java.util.Arrays;​​        





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c = Class.forName(​​ ​​"java.lang.Boolean"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​Class<?>[] in = c.getInterfaces();​​


​​System.out.println(Arrays.toString(in));​​


​​}​​


​​}​​


 没什么好说的,看结果


java中的反射总结_System_06

 

实例7:取得父类

​​public​​          ​​class​​          ​​Demo {​​        


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c = Class.forName(​​ ​​"java.lang.Boolean"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​//注意了,这里不会是数组,why?​​


​​Class<?> su = c.getSuperclass();​​


​​System.out.println(su);​​


​​}​​


​​}​​


 别忘了,java中是单继承,父类只有一个


java中的反射总结_System_07

 

实例8:取得类的全部方法

​​import​​          ​​java.lang.reflect.Method;​​        





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c = Class.forName(​​ ​​"java.lang.Boolean"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​Method[] m = c.getMethods();​​


​​//好吧,这次我就大发慈悲的写个打印列表出来​​


​​for​​ ​​(​​ ​​int​​ ​​i = ​​ ​​0​​ ​​; i < m.length; i++) {​​


​​System.out.println(m[i]);​​


​​}​​


​​}​​


​​}​​


 截取一部分,看看,意思下就行了……这几个例子都比较简单


java中的反射总结_反射类_08

 

实例9:取得本类的全部属性

​​import​​          ​​java.lang.reflect.Field;​​        





​​class​​ ​​Person {​​


​​private​​ ​​String name;​​


​​private​​ ​​int​​ ​​age;​​


​​}​​





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Class<?> c = ​​ ​​null​​ ​​;​​


​​try​​ ​​{​​


​​c = Class.forName(​​ ​​"Person"​​ ​​);​​


​​} ​​ ​​catch​​ ​​(ClassNotFoundException e) {​​


​​e.printStackTrace();​​


​​}​​


​​Field[] f = c.getDeclaredFields();​​


​​for​​ ​​(​​ ​​int​​ ​​i = ​​ ​​0​​ ​​; i < f.length; i++) {​​


​​System.out.println(f[i]);​​


​​}​​


​​}​​


​​}​​


getDeclaredFielsd()方法可以获取全部属性,getFields()只能获取公共属性


java中的反射总结_反射类_09

 

实例10:获取本类中属性的值

​​import​​          ​​java.lang.reflect.Field;​​        





​​class​​ ​​Person {​​


​​public​​ ​​String name;​​


​​private​​ ​​int​​ ​​age;​​





​​public​​ ​​Person(String name, ​​ ​​int​​ ​​age) {​​


​​this​​ ​​.name = name;​​


​​this​​ ​​.age = age;​​


​​}​​


​​}​​





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Person p = ​​ ​​new​​ ​​Person(​​ ​​"zhangsan"​​ ​​,​​ ​​12​​ ​​);​​





​​Class<?> c = p.getClass();​​





​​//获取公共属性的值​​


​​Field f1 = c.getField(​​ ​​"name"​​ ​​);​​


​​//get(p)表明要获取是哪个对象的值​​


​​String str = (String) f1.get(p);​​


​​System.out.println(​​ ​​"姓名: "​​ ​​+ str);​​





​​//获取私有属性的值​​


​​Field f2 = c.getDeclaredField(​​ ​​"age"​​ ​​);​​


​​//age是私有属性,所以要设置安全检查为true​​


​​f2.setAccessible(​​ ​​true​​ ​​);​​


​​int​​ ​​age = (​​ ​​int​​ ​​) f2.get(p);​​


​​System.out.println(​​ ​​"年龄: "​​ ​​+ age);​​


​​}​​


​​}​​


 要注意的是:setAccessible()方法可以设置是否访问和修改私有属性


java中的反射总结_反射类_10

 

坦白说,java学到现在我还没发现什么能亮瞎我钛金眼的知识在里边

每次都是写一堆繁琐的语法实现个小玩意儿,不然就是拼命调用API,拼命的抛异常

让本身显得不够紧凑的代码变得愈发累赘

如果我喜欢一门语言,在我利用它做出东西来之前,它本身的特性必须能够打动我

显然,java并不让我快乐,也许很多程序员跟我一样是被迫使用java的

仅以此来安抚我那颗孤独编码的心,下面接着看内容

 

反射的应用

实例11:通过反射修改属性

​​import​​          ​​java.lang.reflect.Field;​​        





​​class​​ ​​Person {​​


​​private​​ ​​String name;​​





​​public​​ ​​Person(String name) {​​


​​this​​ ​​.name = name;​​


​​}​​





​​public​​ ​​String toString() {​​


​​return​​ ​​"姓名: "​​ ​​+ ​​ ​​this​​ ​​.name;​​


​​}​​


​​}​​





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Person p = ​​ ​​new​​ ​​Person(​​ ​​"王二狗"​​ ​​);​​


​​System.out.println(p);​​


​​Class<?> c = p.getClass();​​





​​//定义要修改的属性​​


​​Field f = c.getDeclaredField(​​ ​​"name"​​ ​​);​​


​​f.setAccessible(​​ ​​true​​ ​​);​​


​​//修改属性,传入要设置的对象和值​​


​​f.set(p, ​​ ​​"张二蛋"​​ ​​);​​


​​System.out.println(p);​​


​​}​​


​​}​​


 几个方法都是有联系的,如果看不懂就先熟悉上面几个例子


java中的反射总结_构造方法_11

 

实例12:通过反射调用方法

​​import​​          ​​java.lang.reflect.Method;​​        





​​class​​ ​​Person {​​


​​public​​ ​​void​​ ​​print(​​ ​​int​​ ​​i) {​​


​​System.out.println(​​ ​​"我在写数字: "​​ ​​+ i);​​


​​}​​





​​public​​ ​​static​​ ​​void​​ ​​say(String str) {​​


​​System.out.println(​​ ​​"我在说: "​​ ​​+ str);​​


​​}​​


​​}​​





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​Person p = ​​ ​​new​​ ​​Person();​​


​​Class<?> c = p.getClass();​​





​​//getMethod()方法需要传入方法名,和参数类型​​


​​Method m1 = c.getMethod(​​ ​​"print"​​ ​​, ​​ ​​int​​ ​​.​​ ​​class​​ ​​);​​


​​//invoke()表示调用的意思,需要传入对象和参数​​


​​m1.invoke(p, ​​ ​​10​​ ​​);​​





​​Method m2 = c.getMethod(​​ ​​"say"​​ ​​, String.​​ ​​class​​ ​​);​​


​​//这里的null表示不由对象调用,也就是静态方法​​


​​m2.invoke(​​ ​​null​​ ​​, ​​ ​​"你妹"​​ ​​);​​


​​}​​


​​}​​


这里演示了一个普通的有参方法和一个静态方法


java中的反射总结_Test_12

既然有参数的都写出来了,那么无参的就更简单了,直接传入一个对象即可

 

实例13:通过反射操作数组

​​import​​          ​​java.lang.reflect.Array;​​        





​​public​​ ​​class​​ ​​Demo {​​


​​public​​ ​​static​​ ​​void​​ ​​main(String[] args) ​​ ​​throws​​ ​​Exception {​​


​​int​​ ​​[] arr = {​​ ​​1​​ ​​,​​ ​​2​​ ​​,​​ ​​3​​ ​​,​​ ​​4​​ ​​,​​ ​​5​​ ​​};​​


​​Class<?> c = arr.getClass().getComponentType();​​





​​System.out.println(​​ ​​"数组类型: "​​ ​​+ c.getName());​​


​​int​​ ​​len = Array.getLength(arr);​​


​​System.out.println(​​ ​​"数组长度: "​​ ​​+ len);​​


​​System.out.print(​​ ​​"遍历数组: "​​ ​​);​​


​​for​​ ​​(​​ ​​int​​ ​​i = ​​ ​​0​​ ​​; i < len; i++) {​​


​​System.out.print(Array.get(arr, i) + ​​ ​​" "​​ ​​);​​


​​}​​


​​System.out.println();​​


​​//修改数组​​


​​System.out.println(​​ ​​"修改前的第一个元素: "​​ ​​+ Array.get(arr, ​​ ​​0​​ ​​));​​


​​Array.set(arr, ​​ ​​0​​ ​​, ​​ ​​3​​ ​​);​​


​​System.out.println(​​ ​​"修改后的第一个元素: "​​ ​​+ Array.get(arr, ​​ ​​0​​ ​​));​​


​​}​​


​​}​​


 这里要注意一点,getComponentType( )返回的是数组元素的Class


java中的反射总结_构造方法_13

 

暂时就写这么多,我看的书中还有反射在工厂模式中的应用

无非是用forName()方法替换一下,没什么可说的

我是个java初级黑,我恨java那种恶心的语法和设计

这都是为了Android,为了打基础,为了适应以后的工作

Fu java……

举报

相关推荐

0 条评论