2013-01-16 44 views

回答

8

反射是一個強大的結構,它經常被底層庫(如Guice和Hibernate)用來使生活更輕鬆。它經常用於需要配置類然後實時實例化的地方。例如:

public Strategy prepare(String clazz, Properties config) throws ClassNotFoundException, InstantiationException, IllegalAccessException { 
    Class<?> clazz = Class.forName(clazz); 
    Strategy strategy = (Strategy) clazz.newInstance(); 
    strategy.initialise(config); 
    return strategy; 
} 

在這裏,clazz參數命名要實例化的類。假定該類將是Strategy類/接口的子類。然後它也通過config參數傳入的設置啓動。這允許高度可配置/動態的環境。

但是,反射通常會導致非常危險的(和惡意的)代碼,因此應該避免反射,除非絕對必要。另外請記住,反射比直接調用要慢。下面是一個從生產系統中抽取的實例,說明如何不使用反射。

private static CacheManager getRawInstance() { 
    lock.lock(); 
    try { 
     final Field field = CacheManager.class.getDeclaredField("singleton"); 
     field.setAccessible(true); // << -- ?? 
     return (CacheManager) field.get(CacheManager.class); 
    } catch (Exception e) { 
     logger.error(e.getMessage(), e); 
     return null; 
    } finally { 
     lock.unlock(); 
    } 
} 

在這裏,ehcache中的私有字段被改變並被訪問。這是完全錯誤的編碼。

+1

等待,Field.setAccessible(真)在生產中使用? ??我猜這是一個有趣的一天,當那個寶石被發現。 – Dan

+0

是的,確實......鎖還把寶石多一點(「同步」發生了什麼?)。當ehcache開始在系統的其他部分開始行爲不當(忽略配置等)時,發現問題。在將它分解出來之後......它被完整保留並帶有註釋作爲警告。這是一個很好的教訓。它說明了反射代碼的危險程度。 –

1

TechExchange在解釋反射方面做得很好。反思似乎是爪哇的一隻黑羊。我總是聽到有人說這是它的錯誤,而且容易出錯,但是當它正確完成時,我發現它非常穩定和高效。我會說避免使用它,並試圖通過編寫本機反射代碼來建立一個自省庫。反思與反思相同,通常只是一個建立在底層反射庫上的庫。如果你正在使用bean,Spring和Apache commons都有很好的工具。

Spring和Apache只是瞄準getters,不幸的是,我不住在bean世界。我不得不使用的一些對象是布爾的'is'方法,並且發現自己編寫反射代碼。

無論如何,這裏是一些簡單的反射代碼,存儲每個公共方法0參數。

public void foo(final Class _class){ 
    List<Method> methods = new ArrayList<Method>(){{ 
     for(Method method : _class.getMethods()) { 

      if(Modifier.isPublic(method.getModifiers()) 
       && method.getGenericParameterTypes().length == 0){ 

      add(method); 
     } 
    }}; 
}