反射技术的应用
前面我们学习了反射机制,接下来我们就进一步来谈谈它的应用。比如我们已经定义了一个集合类,其中的
泛型为String,那我们能向该集合添加其他类型的元素吗?从java的语法上是无法做到的。
ArrayList<String> array = new ArrayList<String>(); array.add("String"); //向集合添加String类型 array.add(123); //无法添加Integer等其他数据类型
如上代码,我们向集合里面添加String是没问题的,但是添加其他类型呢?无疑,编译是无法通过的。那怎
么办呢?在以前我们学集合的时候,曾经有过一个概念叫做伪泛型(编译后的class文件是没有泛型的),我们
可以利用这一点来寻找问题的突破口。当我们运行ArrayList<String>的时候,ArrayList.class会被调进方法区。
调进方法区后,类的加载器就会为ArrayList.class文件创建对象,该文件会被解剖,将add()方法从class文件拿
出来以后直接运行。像这种避开了对象的调用而直接加载class文件的方法能不能为我们解决上述问题呢?应该
说可以的。我们可以使用反射机制直接从方法区中直接调用。通过ArrayList.class的原码,我们发现其中的add
方法传的泛型E,所以我们可以绕过对象,直接走后门。调用这个方法。想要实现这个功能非常简单,我们通
过反射机制获取集合类的class文件对象。通过class文件对象直接调用add方法。之前我们讲过获取对象的三种
方式,所以这里就没必要forName()方法了,使用对象直接调用getClass()方法也可以实现class文件的获取。
//创建集合 ArrayList<String> array = new ArrayList<String>(); //反射获取集合类中的class文件对象 Class c = array.getClass(); ///获取文件中的方法add() Method method = c.getMethod("add",Object.class); //使用invoke()方法运行 method.invoke(array,"string"); method.invoke(array,100); method.invoke(array,100.0); method.invoke(array,true); System.out.println(array); //输出:[string, 100, 100.0, true]
通过以上实验,我们发现这种方法是可行的,其原因在于编译后产生class文件是无泛型约束的,这种现象
称之为泛型的擦除。既然如此,我们就可以利用反射技术来向有泛型约束的集合添加任意类型,所以泛型在这
中技术中已经显得不是很重要了。这里还要特殊的强调一下,当我们往集合中添加了任意类型元素后,首先我
们想到的问题是,它能遍历吗?答案我们都很清楚,不能。所以往集合中添加任意多种类型没有实用的价值。
这里之所以这样做是考察我们是否理解在集合中使用反射技术。
反射技术还可以用于反射文件的配置。比如我们现在有很多个类,但是类的使用是不清楚的,模糊的,可
能是随着需求的变化而变化。而我们又怕修改原码,解决这个方法就可以通过配置文件来实现。反射文件的配
置规定运行的类名和方法名以键值对的形式写在文本中。而我们想要运行某个类的时候,就可以读取配置文即
可。反射技术的优势之处在于类名和方法名都可以以字符串的形式表示。反射文件配置的基本步骤如下:
1.准备配置文件
在eclipse工程的根目录下创建File文件,不妨就叫config.properties,在config.properties文件中配置如下内容:
className = com.gzhxtc.win.Goods methodName = goods
2.IO流读取配置文件(Reader)
在应用类里使用IO流读取配置文件,需要注意的是在工程的根目录下文件名不需要写配置文件的全路径
//IO流读取配置文件 FileReader fleReader = new FileReader("config.properties");
3.将文件中的键值对存储到集合中(Properties)
//创建集合对象 Properties properties = new Properties(); //调用集合的load方法,传递流对象 properties.load(fleReader); fleReader.close();
4. 使用反射技术
//通过Key获取Value String className = properties.getProperty("className"); String methodName = properties.getProperty("methodName"); //反射获取类的class文件对象 Class c = Class.forName(className); Object obj = c.newInstance(); Method method = c.getMethod(methodName); method.invoke(obj);
所以通过以上的例子,我们不难发现这种方式根本不需要修改原码,只需要修改配置文件就行。现代写代
码的基本形式已经趋向于反射的形式了。在上面的配置文件中可以在里面配置多个键值对,把不用的键值对用
“#”进行注释,等想用的使用在解放注释。如果多个键值对没有进行注释,集合会将前面的键值对进行覆盖,最
后只剩下最后一个。这一点是我们需要注意的。
原文地址:https://www.cnblogs.com/Lynnblog/p/8963727.html