2013-01-16 8 views

risposta

8

Reflection è un potente costrutto che viene spesso utilizzato dalle librerie sottostanti come Guice e Hibernate per semplificare la vita. Viene spesso utilizzato dove una classe deve essere configurata e quindi istanziata al volo. Ad esempio:

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; 
} 

Qui, il parametro clazz indica la classe da istanziare. Si presume che la classe sarà una sottoclasse della classe/interfaccia della strategia. Viene quindi avviato anche con le impostazioni passate attraverso il parametro config. Ciò consente un ambiente altamente configurabile/dinamico.

Tuttavia, la riflessione porta spesso a codice molto pericoloso (e malevolo) e per tale motivo, la riflessione dovrebbe essere evitata, a meno che non sia assolutamente necessario. Inoltre, tieni presente che la riflessione è più lenta di una chiamata diretta. Ecco un esempio reale tratto da un sistema di produzione su come NON usare la riflessione.

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(); 
    } 
} 

Qui, il campo privato in ehcache viene modificato e vi si accede. Questa è decisamente una cattiva programmazione.

+1

Aspetta, Field.setAccessible (vero) è stato utilizzato in produzione? ?? Immagino sia stato un giorno interessante in cui è stata trovata quella gemma. – Dan

+0

Sì Dan, infatti ... la serratura ha anche lucidato la gemma un po 'di più (cosa è successo a "sincronizzato"?). Il problema è stato scoperto quando ehcache ha iniziato a comportarsi in modo anomalo in altre parti del sistema (ignorando la configurazione, ecc.). Dopo averlo considerato ... è stato lasciato intatto con un commento come avvertimento. E 'stata una buona lezione. Illustra quanto può essere pericoloso il codice di riflessione. –

1

TechExchange ha svolto un ottimo lavoro spiegando la riflessione. La riflessione sembra essere una pecora nera in Java. Sento sempre persone che dicono che è buggato e soggetto a errori, ma ho trovato che fosse abbastanza stabile ed efficiente quando è fatto bene. Devo dire di evitare di usarlo e provare una libreria di introspezione scrivendo codice di riflessione nativo. L'introspezione è la stessa cosa del riflesso, generalmente solo una libreria costruita su una libreria di riflessione sottostante. Spring e Apache-commons hanno entrambi ottimi strumenti, se si lavora con i fagioli.

Spring e Apache puntano solo ai getter, sfortunatamente, non vivo in un mondo di fagioli. Alcuni degli oggetti con cui ho dovuto lavorare sono metodi booleani "è" e mi sono trovato a scrivere codice di riflessione.

In ogni caso, ecco un semplice codice di riflessione che memorizza tutti i metodi pubblici con 0 argomenti.

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); 
     } 
    }}; 
}