反射(三)——反射技术的应用

反射技术的应用

  前面我们学习了反射机制,接下来我们就进一步来谈谈它的应用。比如我们已经定义了一个集合类,其中的

泛型为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);

  所以通过以上的例子,我们不难发现这种方式根本不需要修改原码,只需要修改配置文件就行。现代写代

码的基本形式已经趋向于反射的形式了。在上面的配置文件中可以在里面配置多个键值对,把不用的键值对用

#”进行注释,等想用的使用在解放注释。如果多个键值对没有进行注释,集合会将前面的键值对进行覆盖,最

后只剩下最后一个。这一点是我们需要注意的。

 

 

 

 

 

猜你喜欢

转载自www.cnblogs.com/Lynnblog/p/8963727.html