6

This question is strongly related to Change private static final field using Java reflection. There, it was asked, how to change a private static final variable.


However, the answers on that question do not work in Java 12+ as you cannot access private variables of java.lang.reflect.Field using Reflection.

When you try to do it despite that, you will end up with a stack trace like:

Exception java.lang.NoSuchFieldException: modifiers
      at Class.getDeclaredField (Class.java:2412)
      at <your call of Field.class.getDeclaredField("modifiers").setAccessible(true)>

Is there any way to change such a constant in those versions?

I could imagine being possible utilizing JNI/JNA.

6
  • Seems similar to stackoverflow.com/q/55401424 Commented Apr 10, 2020 at 15:22
  • 4
    On a general note though, the JVM treats static final fields as constants, so there is no guarantee that the updated value will be used in the program, instead of an old value. Better to find another solution to your problem. Commented Apr 10, 2020 at 15:24
  • Related: yes, but it is for java 11. This was "fixed" in java 12. Commented Apr 10, 2020 at 15:24
  • I know that but I am working with objects, not any compile time constant. Commented Apr 10, 2020 at 15:25
  • 4
    You misunderstand, I'm not just talking about constant expressions, where the value gets inlined by javac. I'm talking about the JIT compiler treating any value in a static final field as a constant. Commented Apr 10, 2020 at 15:26

1 Answer 1

23

You can use Unsafe.

public class Example
{
    // javac will inline static final Strings, so let's say it's Object
    private static final Object changeThis = "xxx";

    public static void main(String... args) throws Exception
    {
        final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        unsafeField.setAccessible(true);
        final Unsafe unsafe = (Unsafe) unsafeField.get(null);

        System.out.println("before = " + changeThis);

        final Field ourField = Example.class.getDeclaredField("changeThis");
        final Object staticFieldBase = unsafe.staticFieldBase(ourField);
        final long staticFieldOffset = unsafe.staticFieldOffset(ourField);
        unsafe.putObject(staticFieldBase, staticFieldOffset, "it works");

        System.out.println("after = " + changeThis);
    }
}

Result:

before = xxx
after = it works
Sign up to request clarification or add additional context in comments.

4 Comments

Tested with jdk15 and jdk16 and it works!
Works with jdk11 and jdk17, tested with some online playground
I get "Symbol is declared in module 'java.base' which does not export package 'jdk.internal.misc'" with Kotlin on java17
Tested with jdk21 and it works !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.