Why does reflection not update the static field?

Can someone explain why the following code crashes? I have the following five classes:

public class TestReplaceLogger {
    public static void main(String[] arv) throws Exception {
        ClassWithFinalFields classWithFinalFields = new ClassWithFinalFields();
        Field field = ClassWithFinalFields.class.getDeclaredField("LOG");

        // Comment this line and uncomment out the next line causes program work
        Logger oldLogger = (Logger)field.get(null);
        //Logger oldLogger = classWithFinalFields.LOG;


        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

        field.set(null, new MockLogger());

        classWithFinalFields.log();
    }
}

public class ClassWithFinalFields {
    public static final Logger LOG = new RealLogger();

    public void log() {
        LOG.log("hello");
    }
}

public interface Logger {
    public void log(String msg);
}

public class RealLogger implements Logger{
    public void log(String msg) {
        System.out.println("RealLogger: " + msg);
    }
}

public class MockLogger implements Logger {
    public void log(String msg) {
        System.out.println("MockLogger: " + msg);
    }
}

What the code is trying to do is use reflection to replace the LOG variable in the ClassWithFinalFields class. Be that as it may, the class throws a IllegalAccessExceptionwhen it tries to set the field at the end TestReplaceLogger.

However, if I replaced

Logger oldLogger = (Logger)field.get(null);

from

Logger oldLogger = classWithFinalFields.LOG;

then the code runs without problems and prints the magazine "MockLogger: hello", as expected.

, , ? , , IllegalAccessException, , . , , , , , , .

, , - , - . , .

- ,

Exception in thread "main" java.lang.IllegalAccessException: Can not set static final org.matthelliwell.reflection.Logger field org.matthelliwell.reflection.ClassWithFinalFields.LOG to org.matthelliwell.reflection.MockLogger
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:73)
at sun.reflect.UnsafeFieldAccessorImpl.throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:77)
at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:77)
at java.lang.reflect.Field.set(Field.java:741)
at org.matthelliwell.reflection.TestReplaceLogger.main(TestReplaceLogger.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
+4
4

api. , , . , Java API -.

Oracle JDK Field , , , fieldAccessor (. Field.getFieldAccessor()). , , , - , .

+4

:

Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

:

Logger oldLogger = (Logger)field.get(null);
+3

, JVM ( @meriton @oleg.lukyrych).

0

We had a similar problem, and it almost made me tear my own hair.
Where this code (simplified) will work fine ...

        Field field = Long.class.getDeclaredField("MIN_VALUE");
        field.get(null);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.get(null);

... this one will raise an "IllegalAccessException"

        Field field = Long.class.getDeclaredField("MIN_VALUE");
        field.get(null);

        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, 1000l);

(for the reasons described above)

0
source

All Articles