Cambio de variables finales a través de la reflexión, ¿por qué la diferencia entre la variable final estática y no estática? -- java campo con reflection campo con static campo con final campo con jls camp Relacionados El problema

changing final variables through reflection, why difference between static and non-static final variable


9
vote

problema

Español

Consulte el código a continuación. Cuando ejecuto el código, puedo cambiar el valor de una variable final no estática. Pero si intento cambiar el valor de una variable estática final, entonces lanza java.lang.IllegalAccessException .

Mi pregunta es ¿la razón por la que no lanza una excepción en el caso de la variable final no estática también o viceversa? ¿Por qué la diferencia?

  import java.lang.reflect.Field; import java.util.Random;  public class FinalReflection {      final static int stmark =  computeRandom();     final int inmark = computeRandom();      public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {         FinalReflection obj = new FinalReflection();         System.out.println(FinalReflection.stmark);         System.out.println(obj.inmark);         Field staticFinalField  = FinalReflection.class.getDeclaredField("stmark");         Field instanceFinalField  = FinalReflection.class.getDeclaredField("inmark");         staticFinalField.setAccessible(true);         instanceFinalField.setAccessible(true);          instanceFinalField.set(obj, 100);         System.out.println(obj.inmark);          staticFinalField.set(FinalReflection.class, 101);         System.out.println(FinalReflection.stmark);      }      private static int computeRandom() {         return new Random().nextInt(5);     } }   
Original en ingles

Please refer to the below code. When I run the code, I am able to change the value of a final non-static variable. But if I try to change the value of a final static variable then it throws java.lang.IllegalAccessException.

My question is why doesn't it throw an exception in case of non-static final variable also or vice versa. Why the difference?

import java.lang.reflect.Field; import java.util.Random;  public class FinalReflection {      final static int stmark =  computeRandom();     final int inmark = computeRandom();      public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {         FinalReflection obj = new FinalReflection();         System.out.println(FinalReflection.stmark);         System.out.println(obj.inmark);         Field staticFinalField  = FinalReflection.class.getDeclaredField("stmark");         Field instanceFinalField  = FinalReflection.class.getDeclaredField("inmark");         staticFinalField.setAccessible(true);         instanceFinalField.setAccessible(true);          instanceFinalField.set(obj, 100);         System.out.println(obj.inmark);          staticFinalField.set(FinalReflection.class, 101);         System.out.println(FinalReflection.stmark);      }      private static int computeRandom() {         return new Random().nextInt(5);     } } 
              
 
 

Lista de respuestas

10
 
vote
vote
La mejor respuesta
 
  FinalReflectionobj = new FinalReflection(); System.out.println(FinalReflection.stmark); System.out.println(obj.inmark); Field staticFinalField  = FinalReflection.class.getDeclaredField("stmark"); Field instanceFinalField  = FinalReflection.class.getDeclaredField("inmark"); staticFinalField.setAccessible(true); instanceFinalField.setAccessible(true);  //EXTRA CODE //Modify the final using reflection Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(staticFinalField, staticFinalField.getModifiers() & ~Modifier.FINAL);   instanceFinalField.set(obj, 100); System.out.println(obj.inmark); staticFinalField.set(FinalReflection.class, 101); System.out.println(FinalReflection.stmark);   

Esta solución no viene sin algunas desventajas, es posible que no funcione en todos los casos:

En caso de un campo final se inicializa a una constante de tiempo de compilación en la declaración de campo, los cambios en el campo final pueden no ser visibles, ya que los usos de esa final El campo se reemplaza en el tiempo de compilación con la constante de tiempo de compilación.

Otro problema es que la especificación permite la optimización agresiva de los campos final . Dentro de un hilo, está permitido reenviar lecturas de un campo true010 con aquellas modificaciones de un campo true1111 que no tienen lugar en el constructor. más sobre esto también se explica en esta pregunta similar. < / p>

 
FinalReflectionobj = new FinalReflection(); System.out.println(FinalReflection.stmark); System.out.println(obj.inmark); Field staticFinalField  = FinalReflection.class.getDeclaredField("stmark"); Field instanceFinalField  = FinalReflection.class.getDeclaredField("inmark"); staticFinalField.setAccessible(true); instanceFinalField.setAccessible(true);  //EXTRA CODE //Modify the final using reflection Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(staticFinalField, staticFinalField.getModifiers() & ~Modifier.FINAL);   instanceFinalField.set(obj, 100); System.out.println(obj.inmark); staticFinalField.set(FinalReflection.class, 101); System.out.println(FinalReflection.stmark); 

This solution does not come without some downsides, it may not work in all cases:

In case a final field is initialized to a compile-time constant in the field declaration, changes to the final field may not be visible, since uses of that final field are replaced at compile time with the compile-time constant.

Another problem is that the specification allows aggressive optimization of final fields. Within a thread, it is permissible to reorder reads of a final field with those modifications of a final field that do not take place in the constructor. More on this is also explained in this similar question.

 
 
     
     
2
 
vote

el javadoc es claro:

Si el campo subyacente es definitivo, el método arroja una excesa ilegalaccessException a menos que se haya establecido (verdadero) que haya tenido éxito para este objeto de campo y el campo no es estático.

Desde una perspectiva JLS, el comportamiento exacto de cómo se debe especificar la reflexión, sino en jls 17.5.4 :

Normalmente, un campo que es definitivo y estático puede no ser modificado.

Una solaida es para Eliminar el modificador final a través de la reflexión .

 

The javadoc is clear:

If the underlying field is final, the method throws an IllegalAccessException unless setAccessible(true) has succeeded for this Field object and the field is non-static.

From a JLS perspective, the exact behaviour of how reflection should work is not specified, but in JLS 17.5.4:

Normally, a field that is final and static may not be modified.

One workaround is to remove the final modifier through reflection.

 
 
     
     
0
 
vote

Para la final, se puede asignar valores diferentes en tiempo de ejecución cuando se inicializa.

  true2  

Por lo tanto, cada instancia tiene un valor diferente del campo a.

Para la final estática, todas las instancias comparten el mismo valor, y no se pueden modificar después de la primera inicializada.

  true3  
 

For final, it can be assigned different values at runtime when initialized.

Class Test{     public final int a; }  Test t1  = new Test(); t1.a = 10; Test t2  = new Test(); t1.a = 20; 

Thus each instance has different value of field a.

For static final, all instances share the same value, and can't be altered after first initialized.

Class TestStatic{    public static final int a; }  Test t1  = new Test(); t1.a = 10; Test t2  = new Test(); t1.a = 20;   // ERROR, CAN'T BE ALTERED AFTER THE FIRST INITIALIZATION. 
 
 
 
 

Relacionados problema

5  Definiendo las constantes de Java utilizando notación de turnos de bits  ( Defining java constants using bit shift notation ) 
Estaba pasando por el código fuente del java.util.HashMap Class y noté que el constructor explícito NO-ARG espera dos constantes: /** * Constructs an em...

0  ¿Qué sucede si se utiliza un operador de fundición en los operadores de turnos?  ( What if a cast operator is used in shift operators ) 
the JLS dice que El tipo de expresión de turnos es el tipo promotido de la mano izquierda operando. Si el tipo promotido del operando de la mano izquie...

69  ¿Orden de ejecución de los parámetros garantiza en Java?  ( Order of execution of parameters guarantees in java ) 
Dada la siguiente función de la función en C : fooFunc( barFunc(), bazFunc() ); El orden de ejecución de barFunc y BazFunc no se especifica, por l...

30  Pruebas de inicialización Seguridad de los campos finales  ( Testing initialization safety of final fields ) 
Estoy tratando de simplemente probar la seguridad de la seguridad de los campos finales garantizados por los JLS. Es para un papel que estoy escribiendo. Sin ...

11  ¿Qué parte de JLS dijo que las clases anónimas no pueden tener clases de miembros públicos / protegidos / privados?  ( Which part of jls said anonymous classes cannot have public protected private me ) 
Considere esta pieza de código: public class TopLevelClass { Cloneable c = new Cloneable() { private int privateField; private void pri...

6  ¿Cuál es la diferencia entre el nombre calificado y una expresión de acceso de campo?  ( What is the difference between qualified name and a field access expression ) 
de la Detalles JLS en el acceso protegido : Sea C ser la clase en la que se declare un miembro protegido. El acceso es permitido solo dentro del cuerpo ...

4  ¿Cómo calificar completamente una clase cuyo nombre del paquete choca con un nombre de miembro local?  ( How to fully qualify a class whose package name collides with a local member nam ) 
OK, aquí hay un muy curioso rompecabezas Java 7 para los especialistas JLS por ahí. La siguiente pieza de código no compilará, ni con Javac ni con Eclipse: ...

12  ¿Es la orden de las operaciones de izquierda a derecha garantizada en Java?  ( Is the left to right order of operations guaranteed in java ) 
Considere esta función: public static final int F(int a, int b) { a = a - 1 + b; // and some stuff return a; } ¿Se requiere para las implem...

92  ¿Por qué no hay métodos estáticos en las interfaces, pero los campos estáticos y las clases internas están bien? [Pre-java8] [duplicado]  ( Why no static methods in interfaces but static fields and inner classes ok pr ) 
Esta pregunta ya tiene respuestas aquí : ¿Por qué no puedo definir un método estático en un Java? ¿I...

5  Java Final Field Compile-Time Manant Expresión constante  ( Java final field compile time constant expression ) 
El texto siguiente es de JLS http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5.3 Incluso entonces, hay una serie de complicaciones. S...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos