reflection Cambia il campo finale statico privato usando la riflessione Java





4 Answers

Se il valore assegnato a un campo static final boolean è noto in fase di compilazione, è una costante. I campi di tipo primitivo o String possono essere costanti in fase di compilazione. Una costante sarà indicata in qualsiasi codice che faccia riferimento al campo. Poiché il campo non viene effettivamente letto in fase di runtime, la sua modifica non avrà alcun effetto.

Le specifiche del linguaggio Java dicono questo:

Se un campo è una variabile costante (§4.12.4), l'eliminazione della parola chiave final o la modifica del suo valore non interromperà la compatibilità con i file binari preesistenti, facendo sì che non vengano eseguiti, ma non vedranno alcun nuovo valore per l'utilizzo del campo a meno che non siano ricompilati. Questo è vero anche se l'uso stesso non è un'espressione costante in fase di compilazione (§15.28)

Ecco un esempio:

class Flag {
  static final boolean FLAG = true;
}

class Checker {
  public static void main(String... argv) {
    System.out.println(Flag.FLAG);
  }
}

Se decompilate il Checker , vedrete che invece di fare riferimento a Flag.FLAG , il codice semplicemente spinge un valore di 1 ( true ) nello stack (istruzione # 3).

0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3:   iconst_1
4:   invokevirtual   #3; //Method java/io/PrintStream.println:(Z)V
7:   return
java reflection static private final

Ho una classe con un campo private static final che, sfortunatamente, ho bisogno di cambiare in fase di esecuzione.

Usando la riflessione ottengo questo errore: java.lang.IllegalAccessException: Can not set static final boolean field

C'è un modo per cambiare il valore?

Field hack = WarpTransform2D.class.getDeclaredField("USE_HACK");
hack.setAccessible(true);
hack.set(null, true);



L'ho anche integrato con la libreria joor

Basta usare

      Reflect.on(yourObject).set("finalFieldName", finalFieldValue);

Inoltre ho risolto un problema con override che le soluzioni precedenti sembrano mancare. Comunque usa questo molto attentamente, solo quando non c'è altra buona soluzione.




Insieme alla risposta di alto livello, potresti usare un approccio un po 'più semplice. FieldUtils classe FieldUtils Apache ha già un metodo particolare che può fare le cose. Per favore, dai un'occhiata al metodo FieldUtils.removeFinalModifier . È necessario specificare l'istanza del campo di destinazione e il flag di forzatura dell'accessibilità (se si gioca con campi non pubblici). Maggiori informazioni puoi trovare here .




Ho appena visto quella domanda su una delle domande dell'intervista, se possibile per modificare la variabile finale con la riflessione o in runtime. Mi sono davvero interessato, quindi quello con cui sono diventato:

 /**
 * @author Dmitrijs Lobanovskis
 * @since 03/03/2016.
 */
public class SomeClass {

    private final String str;

    SomeClass(){
        this.str = "This is the string that never changes!";
    }

    public String getStr() {
        return str;
    }

    @Override
    public String toString() {
        return "Class name: " + getClass() + " Value: " + getStr();
    }
}

Qualche classe semplice con variabile String finale. Quindi nella classe principale import java.lang.reflect.Field;

/**
 * @author Dmitrijs Lobanovskis
 * @since 03/03/2016.
 */
public class Main {


    public static void main(String[] args) throws Exception{

        SomeClass someClass = new SomeClass();
        System.out.println(someClass);

        Field field = someClass.getClass().getDeclaredField("str");
        field.setAccessible(true);

        field.set(someClass, "There you are");

        System.out.println(someClass);
    }
}

L'output sarà il seguente:

Class name: class SomeClass Value: This is the string that never changes!
Class name: class SomeClass Value: There you are

Process finished with exit code 0

Secondo la documentazione https://docs.oracle.com/javase/tutorial/reflect/member/fieldValues.html




Related