本節寫了個Demo測試反射機制的主要方法,有些細節的東西沒有再具體細化,把反射的主要功能都實現了一遍,代碼如下:
public class TestReflect
{
public static void main(String[] args)
{
//測試所有構造函數
getAllConstructors();
//測試私有構造函數
getPrivateConstructor();
//測試運行私有方法
getPrivateMethod();
//測試獲取和設置屬性
getFields();
}
private static void getFields()
{
try
{
//加載類對象
Class<?> c = Class.forName("reflect.domain.Human");
//實例化Human對象
Human human = (Human) c.newInstance();
//獲得Human對象所有屬性
Field[] fields = c.getDeclaredFields();
for(int i = 0, size = fields.length; i < size; i++)
{
Field field = fields[i];
System.out.println(field.toGenericString());
String name = field.getName();
//轉換將屬性名首字母大寫
if(!Character.isUpperCase(name.charAt(0)))
{
name = (new StringBuilder()).append(Character.toUpperCase(name.charAt(0))).append(name.substring(1)).toString();
}
//拼接獲得屬性設置方法名
String setMethod = "set" + name;
//獲得屬性設置Method
Method method = c.getDeclaredMethod(setMethod, new Class[]{String.class});
method.setAccessible(true);
//執行屬性設置方法
method.invoke(human, new Object[]{"ss"});
}
human.introdude();
}
catch(Exception e)
{
//todo
}
}
private static void getPrivateMethod()
{
try
{
Class<?> c = Class.forName("reflect.domain.Human");
Human human = (Human) c.newInstance();
//獲得指定方法名和參數類型的方法
Method method = c.getDeclaredMethod("privateMethod", new Class[]{});
//設置可訪問
method.setAccessible(true);
//觸發執行該方法
method.invoke(human, new Object[]{});
}
catch(Exception e)
{
//todo
}
}
private static void getPrivateConstructor()
{
try
{
Class<?> c = Class.forName("reflect.domain.Human");
//獲得指定參數類型的構造函數
Constructor cons = c.getDeclaredConstructor(new Class[]{String.class});
//設置可訪問
cons.setAccessible(true);
//初始化實例,根據傳入的參數初始化
Human human = (Human) cons.newInstance(new Object[]{"William"});
//執行對象方法
human.publicMethod();
human.introdude();
}
catch(Exception e)
{
//todo
}
}
private static void getAllConstructors()
{
try
{
Class<?> c = Class.forName("reflect.domain.Human");
//獲得所有構造函數
Constructor[] constructors = c.getDeclaredConstructors();
Human human = null;
for(int i = 0, size = constructors.length; i < size; i++)
{
Constructor cons = constructors[i];
cons.setAccessible(true);
//獲得構造函數完整簽名
String consName = cons.toGenericString();
//獲得該構造函數的參數
String[] arg1 = consName.split("\\(");
String[] arg2 = arg1[1].split("\\)");
if(0 == arg2.length)
{
//如果參數爲0,調用無參構造函數實例化
human = (Human) cons.newInstance();
human.introdude();
}
else
{
//否則根據參數個數和類型分別實例化,如果不知道參數類型,也可以用反射機制獲得,這裏不再麻煩
String[] args = arg2[0].split(",");
if(1 == args.length)
{
human = (Human) cons.newInstance(new Object[]{"Ann"});
human.introdude();
}
else if(2 == args.length)
{
human = (Human) cons.newInstance(new Object[]{"Ann", "female"});
human.introdude();
}
}
}
}
catch(Exception e)
{
//todo
}
}
}
反射機制允許一個類使用另一個類,即使當前者被編譯的時候後者還根本不存在。然後,這種能力也要付出代價:
1.喪失了編譯時類型檢查的好處,包括異常檢查。如果程序試圖用反射方式調用不存在或不可訪問的方法,在運行時它可能會失敗,因此需要做好防護措施;
2.執行反射訪問所需要的代碼非常笨拙和冗長。編寫乏味,閱讀困難;
3.性能損失。反射方法調用比普通方法調用慢很多。
以上來自<<Effective Java>>。
因此,在普通的方法調用中不需要使用反射,在一些複雜程序中,而且需要使用在編譯時無法知道的對象時,才考慮使用反射機制。
反射是一些框架技術的核心,比如Spring,Struts2等,對於反射的原理還需要進一步掌握。