在Java中動態執行類的靜態方法
在Java中,通過Class.forName()方法可以動態決定加載哪一個類,這個功能對于相同接口的不同實現來講非常有用。比如對于設計好的數據庫連接池接口,我們可以有多種的接口實現類來完成相同的功能,同時用戶可以簡單的通過修改配置文件來指定實際使用哪一個實現類,在源代碼里面通過讀取配置文件信息,并用Class.forName(configClassName).getInstance()就可以構造一個特定的實現類實例,而不用每次修改源代碼。這樣對于程序來講只用關心接口的定義,用戶只用進行配置文件的設置就完成了同一功能的不同實現的切換。
但是如果實現類需要通過靜態方法來進行初始化的時候,動態加載的過程就會復雜一些。同樣的以數據庫連接池為例,通常連接池的構造函數都會被定義為私有的,而通過自定義的getInstance()靜態方法來得到唯一實例。這種情況下簡單的通過Class.forName().getInstance()就無法正確構造實例。
幸好Java所提供的反射機制(Reflection)為我們提供了完整了探悉類內部結構的方法。通過反射機制,我們能夠完成基本上所有的運行時決定的動作(雖然這一實現要比其他動態語言,比如PHP,的eval()的使用要復雜的多)。
下面通過實際的例子說明如何在運行時動態訪問類的靜態方法。
但是如果實現類需要通過靜態方法來進行初始化的時候,動態加載的過程就會復雜一些。同樣的以數據庫連接池為例,通常連接池的構造函數都會被定義為私有的,而通過自定義的getInstance()靜態方法來得到唯一實例。這種情況下簡單的通過Class.forName().getInstance()就無法正確構造實例。
幸好Java所提供的反射機制(Reflection)為我們提供了完整了探悉類內部結構的方法。通過反射機制,我們能夠完成基本上所有的運行時決定的動作(雖然這一實現要比其他動態語言,比如PHP,的eval()的使用要復雜的多)。
下面通過實際的例子說明如何在運行時動態訪問類的靜態方法。
| ------------------------------------------------------- */ import java.lang.reflect.*; public class myTestClass{ private static Object pLock = new Object(); private static myTestClass p_instance = null; private String s_configName = ""; private boolean b_isFromResource = true; public static Object getInstance(String sConfigName, Boolean bIsFromResource){ synchronized(pLock){ if(null == p_instance){ p_instance =new myTestClass(sConfigName,bIsFromResource); } } return p_instance; } private myTestClass(String sConfigName,Boolean bIsFromResource){ s_configName = sConfigName; b_isFromResource = bIsFromResource.booleanValue(); } public void echoInfo(){ System.out.println("current arguments : configName=["+ s_configName+"],isFromResource=["+b_isFromResource+"]"); } public static void main(String[] args) throws Exception{ // 設置方法的傳入參數的類型. Class[] parameterTypes = new Class[]{ java.lang.String.class, java.lang.Boolean.class }; Method mGetInstance = null; String className = "myTestClass"; Class curTestClass = Class.forName(className); try{ mGetInstance = curTestClass.getMethod("getInstance",parameterTypes); } catch(NoSuchMethodException e){ e.printStackTrace(); mGetInstance = null; } if(mGetInstance != null){ myTestClass pObj = (myTestClass) mGetInstance.invoke(null,new Object[]{ "src/myconfig.properties", Boolean.FALSE } ); pObj.echoInfo(); } else{ throw new Exception("myTest Init Failed from class" + className + System.getProperty("line.seperator","") + "method getInstance(String, Boolean) exists."); } } } |