认识Java中的反射机制以及配置文件的应用

  当程序运行时,允许改变程序的结构或者程序的变量类型,开发这种程序的语言被称为动态语言。Java并不具备这种机制所以我们认为Java不是动态语言。但是它具有一个与动态息息相关的机制——反射。

类类型(class类型)

  在Java面向对象程序设计中接触到最多的就是类,将类实例化之后便可以称为是对象。在Java万物均是对象的设计理念中,类也是一种对象!类是由类类型(java.lang.Class)进行实例化后的对象。如何理解类作为一种对象的存在呢?

public class Test(){
    TestClass tc = new TestClass();
    
    Class c1 = TestClass.class;
    Class c2 = tc.getClass();
    
    Class c3 = null;
    try{
        c3 = Class.forName("com.test.TestClass");
    }catch(Exception e){
        e.printStackTrace();
    }
}

  在上述代码中c1,c2,c3都是TestClass的类类型,特别的对于三个对象 c1,c2,c3 有着 c1==c2, c2==c3 的关系。这表明一个类只有可能是一个类类型的实例化对象。

  在了解类类型后我们可以知道,通过实例化类的类类型也可以获得这个类,例如调用 c1/c2/c3的newInstance()方法。

方法的反射

  在获取了类对象后,我们可以调用对象的getMethod()方法来获取类中的方法,这个方法返回的是一个Method类的对象,例如:

Class c = Class.forName(className);
Constructor con = c.getConstructor();
Object object = con.newInstance();
Method method = c.getMethod(methodName);

  要如何执行一个这样获取出来的方法呢?Method类的对象提供了一个invoke方法,我们需要传入执行这个对象的类对象。在调用invoke方法后,系统会对传入的类对象进行检测,如果类对象包含这个方法那么这个方法就会被执行。其中还有其他的权限检测以及调用方法检测这里不做展开。

配置文件的编写以及使用

  配置文件是一个键值对组成的文本文件,例如:

className=TestClass
methodName=say

  等号前面的被称为键,等号后的被称为值,我们可以通过使用Properties类对象来获取键所对应的值来达到不用打开源文件即可对代码进行修改的操作。

  配置文件是一个完善代码开闭原则的一种方法。在没有使用配置文件之前,对代码中的不同子类对象调用方法时必须打开代码文件进行修改,这显然是不符合开闭原则的。例如:客户一开始的要求

public class Test(){
    public static void main(String args[]){
        //客户要求沏一壶乌龙
        Tea wulong = new WuLong();
        wulong.makeTea();
    }
}

public class WuLong() extends Tea{
    public void makeTea(){
        System.out.println("沏一壶乌龙");
    }
}
public class MaoJian() extends Tea{
    public void makeTea(){
        System.out.println("沏一壶毛尖");
    }
}

  但随后客户便更改了要求

public class Test(){
    public static void main(String args[]){
        //客户要求沏一壶乌龙
        //Tea wulong = new WuLong();
        //wulong.makeTea();
        //客户改成要求沏一壶毛尖
        Tea maojian = new MaoJian();
        maojian.makeTea();
    }
}

  最后客户又改回了原来的需求

public class Test(){
    public static void main(String args[]){
        //客户要求沏一壶乌龙
        //Tea wulong = new WuLong();
        //wulong.makeTea();
        //客户改成要求沏一壶毛尖
        //Tea maojian = new MaoJian();
        //maojian.makeTea();
        //客户重新要求沏一壶乌龙
        Tea wulong = new WuLong();
        wulong.makeTea();
    }
}

  改需求的过程中只能不断地打开源代码去进行修改。但当我们使用配置文件之后我们可以轻松地解决这类问题而不用去修改源代码。使用配置文件之后代码如下:

public class Test(){
    public static void main(String args[]){
        String className, methodName;
        //客户要求沏一壶乌龙
           try {
            //读取配置文件
            Properties prop = new Properties();
            FileReader fr = new FileReader("TeaProp");  //读取配置文件
            prop.load(fr);   //加载相关配置
            fr.close();      //关闭文件读取

            //读取属性
            className = prop.getProperty("className");
            methodName = prop.getProperty("methodName");
        } catch (Exception e) {
            e.printStackTrace();
        }
           //反射
        try{
            Class c = Class.forName(className);
            Constructor con = c.getConstructor();
            Object object = con.newInstance();
            Method method = c.getMethod(methodName);

            //完成客户需求
            method.invoke(object);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

  配置文件如下:

className=WuLong
methodName=makeTea

  如果客户要求更改我们也只需要打开配置文件将className的值进行修改即可,满足了开闭原则。

后记

  这次的学习仅仅只是粗略的了解了反射机制以及利用反射机制与配置文件对代码进行开闭性原则的完善,关于反射机制以及配置文件的运用仍有许多没有涉及到的地方。


初めて会ったの日から 僕の心の全てを奪った