2012-12-31 10 views
5

Recentemente mi sono imbattuto in Change private static final field using Java reflection e nella classe EverythingIsTrue dei poligenelubrificanti testati, funziona perfettamente, System.out.format("Everything is %s", false); stampe Everything is true in effetti. Ma quando cambio il codice comeNon è possibile modificare il campo finale statico utilizzando java reflection?

public class EverythingIsTrue { 

    public static final boolean FALSE = false; 

    static void setFinalStatic(Field field, Object newValue) throws Exception { 
     field.setAccessible(true); 
     Field modifiersField = Field.class.getDeclaredField("modifiers"); 
     modifiersField.setAccessible(true); 
     modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); 
     field.set(null, newValue); 
    } 

    public static void main(String[] args) throws Exception { 
     setFinalStatic(EverythingIsTrue.class.getField("FALSE"), true); 
     System.out.format("Everything is %s", FALSE); 
    } 
} 

esso stampa

Everything is false 

Qualcuno sa perché? SetFinalStatic funziona davvero o no?

risposta

13

Quando si accede a campi finali statici primitivi, il compilatore Java assume che il valore è una costante e incorpora il valore anziché generare codice che accede al campo. Ciò significa che il compilatore verrà sostituito con il riferimento al campo FALSE con il valore false. Se usi la reflection per accedere al campo, vedrai che il valore del campo è effettivamente cambiato.

Questo non funzionerà per i campi non primitivi, poiché il valore di un riferimento oggetto non può essere sottolineato al momento della compilazione.

+1

che è esattamente la stessa risposta come il mio - solo con più parole! – dty

+0

@dty sembra che siano infinite anche più parole;) –

+0

Ho cancellato la mia risposta come la tua era stata accettata e la mia non aggiungeva alcun valore - solo brevità! ;-) – dty

17

È possibile evitare l'inlining del compilatore rendendo il valore un risultato di una chiamata di metodo, anche fittizia.

public class Main { 
    // value is not known at compile time, so not inlined 
    public static final boolean FLAG = Boolean.parseBoolean("false"); 

    static void setFinalStatic(Class clazz, String fieldName, Object newValue) throws NoSuchFieldException, IllegalAccessException { 
     Field field = clazz.getDeclaredField(fieldName); 
     field.setAccessible(true); 
     Field modifiers = field.getClass().getDeclaredField("modifiers"); 
     modifiers.setAccessible(true); 
     modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); 
     field.set(null, newValue); 
    } 

    public static void main(String... args) throws Exception { 
     System.out.printf("Everything is %s%n", FLAG); 
     setFinalStatic(Main.class, "FLAG", true); 
     System.out.printf("Everything is %s%n", FLAG); 
    } 
} 

stampe

Everything is false 
Everything is true 
+0

È fantastico! Usando un metodo generico puoi creare un metodo fittizio per non primitivi 'statico T placeHolder() {return null; } ' – flakes

+0

@ mc-emperor, la versione precedente era più leggibile. – dit

+0

@dit È l'output della console, quindi non dovrebbe essere formattato come se fosse codice sorgente. –

Problemi correlati