2013-04-12 13 views
6

Desidero progettare una classe per dimostrare l'immutabilità, in modo incrementale.Proteggi le variabili finali dalla riflessione

seguito è una semplice classe

public class ImmutableWithoutMutator { 
    private final String firstName; 
    private final String lastName; 
    private final int age; 

    public ImmutableWithoutMutator(final String firstName, final String lastName, final int age) { 
     this.firstName = firstName; 
     this.lastName = lastName; 
     this.age = age; 
    } 

    @Override 
    public String toString() { 
     return String.format(
       "ImmutableWithoutMutator [age=%s, firstName=%s, lastName=%s]", 
       age, firstName, lastName); 
    } 
} 

ora posso ancora breccia nel utilizzando la riflessione, utilizzando il seguente codice.

import java.lang.reflect.Field; 

public class BreakImmutableUsingReflection { 
    public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException { 
     ImmutableWithoutMutator immMutator = new ImmutableWithoutMutator(
       "firstName", "lastName", 2400); 
     System.out.println(immMutator); 

     // now lets try changing value using reflection 
     Field f = ImmutableWithoutMutator.class.getDeclaredField("age"); 
     f.setAccessible(true); 
     f.set(immMutator, 2000); 

     System.out.println(immMutator); 
    } 
} 

La mia domanda è, non ho modificato i Modificatori per i campi utilizzando l'API di riflessione. Quindi come il codice è ancora in grado di modificare i campi finali?

+0

Possibile duplicato di http://stackoverflow.com/questions/1615163/modifying-final-fields-in-java?rq=1 – Patashu

risposta

10

Questo è il comportamento previsto, è solo qualcosa che non si dovrebbe fare.

Dalla documentazione per Field.set:

Se il campo sottostante è definitiva, il metodo genera un IllegalAccessException meno setAccessible (vero) è riuscita per questo oggetto campo e il campo è non statico. Impostare un campo finale in questo modo è significativo solo durante la deserializzazione o la ricostruzione di istanze di classi con campi finali vuoti, prima che siano resi disponibili per l'accesso da parte di altre parti di un programma. L'utilizzo in qualsiasi altro contesto potrebbe avere effetti imprevedibili, compresi casi in cui altre parti di un programma continuano a utilizzare il valore originale di questo campo.

Ora, se poi si vuole discutere questa viola tutti i tipi di protezione, è necessario chiedersi perché hai il codice non ti fidi di essere sano di mente in esecuzione con autorizzazioni sufficienti per chiamare field.setAccessible(true). Fondamentalmente, la protezione viene fornita dal responsabile della sicurezza, ma se stai utilizzando un gestore della sicurezza che ti impedisce di farlo, puoi spararti ai piedi.

+4

'if (author.getName(). Equals (" Jon Skeet ")) { this.upvote(); } else {this.readAnswer(); } ' –

+0

@ Jon-skeet Grazie per la spiegazione dettagliata. – Vivek

2

È possibile proteggere da setAccessible utilizzando SecurityManager. Puoi specificarlo sulla riga di comando o crearlo dinamicamente, come lo fanno here.

Ma anche se proteggi da riflessioni il tuo codice non sarebbe ancora protetto da librerie di modifica bytecode come ASM.

Quindi non si deve fare affidamento sul fatto che i campi siano definitivi.

Problemi correlati