核心反射機制 (core reflection facility),package java.lang.reflect 提供訪問任意 class 的能力,給定一 Class 可以拿到 Constructor、Method 和 Field,它們可以對 class 進行調用,像是 Method.invoke 就可以讓你調用該 class 的方法。
反射機制雖然方便,但也要付出一點代價,像是
- 損失編譯時類型檢查的優勢,像是某變數為 String 誤用為 Integer,這種錯誤一般在編譯時就會發生錯誤,但使用反射機制,就變成在執行時才會發生例外。
- 執行反射訪問所需要的程式碼不易閱讀且冗長。
- 效能損失,使用反射機制調用比普通方法慢許多。
以下程式碼中 args[0] 為 java.util.HashMap 或是 java.util.TreeSet,它的輸出結果就會不一樣。這類的程式碼可以使用在服務提供者框架 (service provider framework),同時也顯示出兩個缺點,第一為產生非常多的例外要處理,若不使用反射機制,上述的錯誤都會在編譯時發生錯誤。第二就是冗長的程式碼,一般調用 constructor 只需要一行,但是透過反射機制的程式碼相當冗長。
public static void main(String[] args) {
// Translate the class name into a Class object
Class<? extends Set<String>> cl = null;
try {
cl = (Class<? extends Set<String>>) // Unchecked cast!
Class.forName(args[0]);
} catch (ClassNotFoundException e) {
fatalError("Class not found.");
}
// Get the constructor
Constructor<? extends Set<String>> cons = null;
try {
cons = cl.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
fatalError("No parameterless constructor");
}
// Instantiate the set
Set<String> s = null;
try {
s = cons.newInstance();
} catch (IllegalAccessException e) {
fatalError("Constructor not accessible");
} catch (InstantiationException e) {
fatalError("Class not instantiable.");
} catch (InvocationTargetException e) {
fatalError("Constructor threw " + e.getCause());
} catch (ClassCastException e) {
fatalError("Class doesn't implement Set");
}
// Exercise the set
s.addAll(Arrays.asList(args).subList(1, args.length));
System.out.println(s);
}
private static void fatalError(String msg) {
System.err.println(msg);
System.exit(1);
}
反射機制為一強大的功能,固有其存在的價值,但是缺點就是使用者變成與一個未知的 class 作溝通,盡量只使用反射機制來生成實體,並由其介面或 super class 來使用它。 轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2021/03/effective-java-65-interface-reflection.html
沒有留言:
張貼留言