0

So, I made a ReflectUtil class with some useful methods that allow me to access the java reflection API in a fast and simple way. Based on this the method forceCall can change the value of a private and final field.

This example works absolutely fine:

ReflectUtil.forceCall(Boolean.class, null, "FALSE", true);
System.out.println(String.format("Everything is %s", false));

The output is: Everything is true (so my method is working).

But this just isn't working (it also doesn't work if i try it without my ReflectUtil class):

public class JustForTestingPurposes {
    private static final String field = "no";

    public static void main(String[] args) throws Exception {
        ReflectUtil.forceCall(JustForTestingPurposes.class, null, "field", "yes");
        System.out.println(String.format("Is this working? %s", field));
    }

}

The output is: Is this working? no

I thought, maybe it's because of the way how java assigns values, so I added a 1 sec sleep before executing the code in the main method, with no success.

fluse1367
  • 45
  • 7
  • Does this answer your question? https://stackoverflow.com/a/3301720/4417924 – Jason Mar 27 '20 at 21:19
  • @Jason I think you didn't read my post well. I even referred to this post you linked. – fluse1367 Mar 27 '20 at 21:21
  • Have you read this comment under accepted answer in question linked by you at start of your post https://stackoverflow.com/questions/3301635/change-private-static-final-field-using-java-reflection#comment30350617_3301720? – Pshemo Mar 27 '20 at 21:25

1 Answers1

1

This is how constants work in java.

When a java program is compiled, all references to a compile-time-constant (using a literal or maybe <Classname>.class or similar)are replaced with the constant itself.

You should be able to bypass this by assigning it to the return value of a method or using the new operator(the following example contains both):

private static final String field = getNo();
private String getNo(){
    return new String("no");
}
dan1st
  • 12,568
  • 8
  • 34
  • 67
  • Hm, didn't know that. That explains a lot. Thanks! – fluse1367 Mar 27 '20 at 21:23
  • 1
    Either the method or the `new` would do. The key phrase is *compile-time constant*. – Tom Hawtin - tackline Mar 27 '20 at 21:24
  • Yes, java does a few optimisations :) – dan1st Mar 27 '20 at 21:24
  • 1
    `.class` is not a compile-time constant. And, as TomHawtin-tackline said, there is no need for `new String("no")`. Using `private String getNo(){ return "no"; }` would work as well. In fact, just declaring the variable as `private static final String field = "no".toString();` would be enough. But unlike `final` instance fields, changing `static final` fields via runtime is an unsupported feature, even when using Reflection. It's not guaranteed to work at all. – Holger Mar 30 '20 at 11:01
  • Yea but I am not sure what will be optimized away – dan1st Mar 30 '20 at 11:03
  • 1
    This has nothing to do with optimizations. The behavior of compile-time constants is precisely specified in the JLS. See [Does the JLS require inlining of final String constants?](https://stackoverflow.com/q/39386014/2711488) and the definition of [constant expressions in JLS, §15.28.](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28) – Holger Mar 30 '20 at 11:08