Is there a limit to overriding final static field with Reflection?











up vote
14
down vote

favorite
3












I have been faced in some of my Unit test with a strange behaviour with Reflection on final static field. Below is an example illustrating my issue.



I have a basic Singleton class that holds an Integer



public class BasicHolder {
private static BasicHolder instance = new BasicHolder();

public static BasicHolder getInstance() {
return instance;
}

private BasicHolder() {
}

private final static Integer VALUE = new Integer(0);

public Integer getVALUE() {
return VALUE;
}

}


My test case is looping and setting through Reflection the VALUE to the iteration index and then asserting that the VALUE is rightfully equal to the iteration index.



class TestStaticLimits {
private static final Integer NB_ITERATION = 10_000;

@Test
void testStaticLimit() {

for (Integer i = 0; i < NB_ITERATION; i++) {
setStaticFieldValue(BasicHolder.class, "VALUE", i);
Assertions.assertEquals(i, BasicHolder.getInstance().getVALUE(), "REFLECTION DID NOT WORK for iteration "+i);
System.out.println("iter " + i + " ok" );

}
}

private static void setStaticFieldValue(final Class obj, final String fieldName, final Object fieldValue) {
try {
final Field field = obj.getDeclaredField(fieldName);
field.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, fieldValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Error while setting field [" + fieldName + "] on object " + obj + " Message " + e.getMessage(), e);
}
}

}


The result is quite surprising because it's not constant,
my test fails around iteration ~1000 but it never seems to be always the same.



Anyone has already faced this issue ?










share|improve this question




















  • 1




    I have reopened this question, as it is not a duplicate of stackoverflow.com/questions/3301635/…. OP clearly understands how to modify a private static final field.
    – Jacob G.
    Nov 20 at 15:15








  • 3




    I have managed to repro this ideone.com/bZ7nmR
    – Andy Turner
    Nov 20 at 15:20






  • 10




    It could be that after ~1000 iterations the JIT kicks in and compiles the loop into native code. And since the field "is expected to be final" the JIT does inline the current value of the field
    – Thomas Kläger
    Nov 20 at 15:22








  • 6




    @ThomasKläger is correct. The program succeeds when run with -Djava.compiler=NONE. Write an answer and claim your points!
    – Jacob G.
    Nov 20 at 15:26








  • 3




    @Hulk private final static Integer VALUE = new Integer(0); is not a constant variable.
    – Sotirios Delimanolis
    Nov 20 at 15:34















up vote
14
down vote

favorite
3












I have been faced in some of my Unit test with a strange behaviour with Reflection on final static field. Below is an example illustrating my issue.



I have a basic Singleton class that holds an Integer



public class BasicHolder {
private static BasicHolder instance = new BasicHolder();

public static BasicHolder getInstance() {
return instance;
}

private BasicHolder() {
}

private final static Integer VALUE = new Integer(0);

public Integer getVALUE() {
return VALUE;
}

}


My test case is looping and setting through Reflection the VALUE to the iteration index and then asserting that the VALUE is rightfully equal to the iteration index.



class TestStaticLimits {
private static final Integer NB_ITERATION = 10_000;

@Test
void testStaticLimit() {

for (Integer i = 0; i < NB_ITERATION; i++) {
setStaticFieldValue(BasicHolder.class, "VALUE", i);
Assertions.assertEquals(i, BasicHolder.getInstance().getVALUE(), "REFLECTION DID NOT WORK for iteration "+i);
System.out.println("iter " + i + " ok" );

}
}

private static void setStaticFieldValue(final Class obj, final String fieldName, final Object fieldValue) {
try {
final Field field = obj.getDeclaredField(fieldName);
field.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, fieldValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Error while setting field [" + fieldName + "] on object " + obj + " Message " + e.getMessage(), e);
}
}

}


The result is quite surprising because it's not constant,
my test fails around iteration ~1000 but it never seems to be always the same.



Anyone has already faced this issue ?










share|improve this question




















  • 1




    I have reopened this question, as it is not a duplicate of stackoverflow.com/questions/3301635/…. OP clearly understands how to modify a private static final field.
    – Jacob G.
    Nov 20 at 15:15








  • 3




    I have managed to repro this ideone.com/bZ7nmR
    – Andy Turner
    Nov 20 at 15:20






  • 10




    It could be that after ~1000 iterations the JIT kicks in and compiles the loop into native code. And since the field "is expected to be final" the JIT does inline the current value of the field
    – Thomas Kläger
    Nov 20 at 15:22








  • 6




    @ThomasKläger is correct. The program succeeds when run with -Djava.compiler=NONE. Write an answer and claim your points!
    – Jacob G.
    Nov 20 at 15:26








  • 3




    @Hulk private final static Integer VALUE = new Integer(0); is not a constant variable.
    – Sotirios Delimanolis
    Nov 20 at 15:34













up vote
14
down vote

favorite
3









up vote
14
down vote

favorite
3






3





I have been faced in some of my Unit test with a strange behaviour with Reflection on final static field. Below is an example illustrating my issue.



I have a basic Singleton class that holds an Integer



public class BasicHolder {
private static BasicHolder instance = new BasicHolder();

public static BasicHolder getInstance() {
return instance;
}

private BasicHolder() {
}

private final static Integer VALUE = new Integer(0);

public Integer getVALUE() {
return VALUE;
}

}


My test case is looping and setting through Reflection the VALUE to the iteration index and then asserting that the VALUE is rightfully equal to the iteration index.



class TestStaticLimits {
private static final Integer NB_ITERATION = 10_000;

@Test
void testStaticLimit() {

for (Integer i = 0; i < NB_ITERATION; i++) {
setStaticFieldValue(BasicHolder.class, "VALUE", i);
Assertions.assertEquals(i, BasicHolder.getInstance().getVALUE(), "REFLECTION DID NOT WORK for iteration "+i);
System.out.println("iter " + i + " ok" );

}
}

private static void setStaticFieldValue(final Class obj, final String fieldName, final Object fieldValue) {
try {
final Field field = obj.getDeclaredField(fieldName);
field.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, fieldValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Error while setting field [" + fieldName + "] on object " + obj + " Message " + e.getMessage(), e);
}
}

}


The result is quite surprising because it's not constant,
my test fails around iteration ~1000 but it never seems to be always the same.



Anyone has already faced this issue ?










share|improve this question















I have been faced in some of my Unit test with a strange behaviour with Reflection on final static field. Below is an example illustrating my issue.



I have a basic Singleton class that holds an Integer



public class BasicHolder {
private static BasicHolder instance = new BasicHolder();

public static BasicHolder getInstance() {
return instance;
}

private BasicHolder() {
}

private final static Integer VALUE = new Integer(0);

public Integer getVALUE() {
return VALUE;
}

}


My test case is looping and setting through Reflection the VALUE to the iteration index and then asserting that the VALUE is rightfully equal to the iteration index.



class TestStaticLimits {
private static final Integer NB_ITERATION = 10_000;

@Test
void testStaticLimit() {

for (Integer i = 0; i < NB_ITERATION; i++) {
setStaticFieldValue(BasicHolder.class, "VALUE", i);
Assertions.assertEquals(i, BasicHolder.getInstance().getVALUE(), "REFLECTION DID NOT WORK for iteration "+i);
System.out.println("iter " + i + " ok" );

}
}

private static void setStaticFieldValue(final Class obj, final String fieldName, final Object fieldValue) {
try {
final Field field = obj.getDeclaredField(fieldName);
field.setAccessible(true);
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, fieldValue);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Error while setting field [" + fieldName + "] on object " + obj + " Message " + e.getMessage(), e);
}
}

}


The result is quite surprising because it's not constant,
my test fails around iteration ~1000 but it never seems to be always the same.



Anyone has already faced this issue ?







java reflection






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 20 at 16:07









Sotirios Delimanolis

205k39467558




205k39467558










asked Nov 20 at 15:07









Samy Elaiassi

407310




407310








  • 1




    I have reopened this question, as it is not a duplicate of stackoverflow.com/questions/3301635/…. OP clearly understands how to modify a private static final field.
    – Jacob G.
    Nov 20 at 15:15








  • 3




    I have managed to repro this ideone.com/bZ7nmR
    – Andy Turner
    Nov 20 at 15:20






  • 10




    It could be that after ~1000 iterations the JIT kicks in and compiles the loop into native code. And since the field "is expected to be final" the JIT does inline the current value of the field
    – Thomas Kläger
    Nov 20 at 15:22








  • 6




    @ThomasKläger is correct. The program succeeds when run with -Djava.compiler=NONE. Write an answer and claim your points!
    – Jacob G.
    Nov 20 at 15:26








  • 3




    @Hulk private final static Integer VALUE = new Integer(0); is not a constant variable.
    – Sotirios Delimanolis
    Nov 20 at 15:34














  • 1




    I have reopened this question, as it is not a duplicate of stackoverflow.com/questions/3301635/…. OP clearly understands how to modify a private static final field.
    – Jacob G.
    Nov 20 at 15:15








  • 3




    I have managed to repro this ideone.com/bZ7nmR
    – Andy Turner
    Nov 20 at 15:20






  • 10




    It could be that after ~1000 iterations the JIT kicks in and compiles the loop into native code. And since the field "is expected to be final" the JIT does inline the current value of the field
    – Thomas Kläger
    Nov 20 at 15:22








  • 6




    @ThomasKläger is correct. The program succeeds when run with -Djava.compiler=NONE. Write an answer and claim your points!
    – Jacob G.
    Nov 20 at 15:26








  • 3




    @Hulk private final static Integer VALUE = new Integer(0); is not a constant variable.
    – Sotirios Delimanolis
    Nov 20 at 15:34








1




1




I have reopened this question, as it is not a duplicate of stackoverflow.com/questions/3301635/…. OP clearly understands how to modify a private static final field.
– Jacob G.
Nov 20 at 15:15






I have reopened this question, as it is not a duplicate of stackoverflow.com/questions/3301635/…. OP clearly understands how to modify a private static final field.
– Jacob G.
Nov 20 at 15:15






3




3




I have managed to repro this ideone.com/bZ7nmR
– Andy Turner
Nov 20 at 15:20




I have managed to repro this ideone.com/bZ7nmR
– Andy Turner
Nov 20 at 15:20




10




10




It could be that after ~1000 iterations the JIT kicks in and compiles the loop into native code. And since the field "is expected to be final" the JIT does inline the current value of the field
– Thomas Kläger
Nov 20 at 15:22






It could be that after ~1000 iterations the JIT kicks in and compiles the loop into native code. And since the field "is expected to be final" the JIT does inline the current value of the field
– Thomas Kläger
Nov 20 at 15:22






6




6




@ThomasKläger is correct. The program succeeds when run with -Djava.compiler=NONE. Write an answer and claim your points!
– Jacob G.
Nov 20 at 15:26






@ThomasKläger is correct. The program succeeds when run with -Djava.compiler=NONE. Write an answer and claim your points!
– Jacob G.
Nov 20 at 15:26






3




3




@Hulk private final static Integer VALUE = new Integer(0); is not a constant variable.
– Sotirios Delimanolis
Nov 20 at 15:34




@Hulk private final static Integer VALUE = new Integer(0); is not a constant variable.
– Sotirios Delimanolis
Nov 20 at 15:34












2 Answers
2






active

oldest

votes

















up vote
9
down vote



accepted










The JLS mentions that modifying final fields after construction is problematic - see
17.5. final Field Semantics




Fields declared final are initialized once, but never changed under normal circumstances. The detailed semantics of final fields are somewhat different from those of normal fields. In particular, compilers have a great deal of freedom to move reads of final fields across synchronization barriers and calls to arbitrary or unknown methods. Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded.




and 17.5.3. Subsequent Modification of final Fields:




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.




In addition to that, the JavaDocs of Field.set also include a warning about this:




Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.




It seems that what we are witnessing here is the JIT taking advantage of the reordering and caching possibilities granted by the Language Specification.






share|improve this answer






























    up vote
    4
    down vote













    It's because of the JIT optimization. To prove this, disable it using the following VM option:



    -Djava.compiler=NONE


    In this case all 10_000 iterations will work.



    Or, exclude the BasicHolder.getVALUE method from being compiled:



    -XX:CompileCommand=exclude,src/main/BasicHolder.getVALUE


    What actually happens under the hood is that after nth iteration, the hot method getVALUE is being compiled and static final Integer VALUE is being aggressively optimized (this is really the just-in-time constant1). From this point, the assertion starts to fail.



    The output of the -XX:+PrintCompilation with my comments:



    val 1       # System.out.println("val " + BasicHolder.getInstance().getVALUE());
    val 2
    val 3
    ...
    922 315 3 src.main.BasicHolder::getInstance (4 bytes) # Method compiled
    922 316 3 src.main.BasicHolder::getVALUE (4 bytes) # Method compiled
    ...
    val 1563 # after compilation
    val 1563
    val 1563
    val 1563
    ...




    1 - JVM Anatomy Park: Just-In-Time Constants.






    share|improve this answer























    • @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
      – Samy Elaiassi
      Nov 20 at 16:50











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53395929%2fis-there-a-limit-to-overriding-final-static-field-with-reflection%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    9
    down vote



    accepted










    The JLS mentions that modifying final fields after construction is problematic - see
    17.5. final Field Semantics




    Fields declared final are initialized once, but never changed under normal circumstances. The detailed semantics of final fields are somewhat different from those of normal fields. In particular, compilers have a great deal of freedom to move reads of final fields across synchronization barriers and calls to arbitrary or unknown methods. Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded.




    and 17.5.3. Subsequent Modification of final Fields:




    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.




    In addition to that, the JavaDocs of Field.set also include a warning about this:




    Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.




    It seems that what we are witnessing here is the JIT taking advantage of the reordering and caching possibilities granted by the Language Specification.






    share|improve this answer



























      up vote
      9
      down vote



      accepted










      The JLS mentions that modifying final fields after construction is problematic - see
      17.5. final Field Semantics




      Fields declared final are initialized once, but never changed under normal circumstances. The detailed semantics of final fields are somewhat different from those of normal fields. In particular, compilers have a great deal of freedom to move reads of final fields across synchronization barriers and calls to arbitrary or unknown methods. Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded.




      and 17.5.3. Subsequent Modification of final Fields:




      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.




      In addition to that, the JavaDocs of Field.set also include a warning about this:




      Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.




      It seems that what we are witnessing here is the JIT taking advantage of the reordering and caching possibilities granted by the Language Specification.






      share|improve this answer

























        up vote
        9
        down vote



        accepted







        up vote
        9
        down vote



        accepted






        The JLS mentions that modifying final fields after construction is problematic - see
        17.5. final Field Semantics




        Fields declared final are initialized once, but never changed under normal circumstances. The detailed semantics of final fields are somewhat different from those of normal fields. In particular, compilers have a great deal of freedom to move reads of final fields across synchronization barriers and calls to arbitrary or unknown methods. Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded.




        and 17.5.3. Subsequent Modification of final Fields:




        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.




        In addition to that, the JavaDocs of Field.set also include a warning about this:




        Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.




        It seems that what we are witnessing here is the JIT taking advantage of the reordering and caching possibilities granted by the Language Specification.






        share|improve this answer














        The JLS mentions that modifying final fields after construction is problematic - see
        17.5. final Field Semantics




        Fields declared final are initialized once, but never changed under normal circumstances. The detailed semantics of final fields are somewhat different from those of normal fields. In particular, compilers have a great deal of freedom to move reads of final fields across synchronization barriers and calls to arbitrary or unknown methods. Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded.




        and 17.5.3. Subsequent Modification of final Fields:




        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.




        In addition to that, the JavaDocs of Field.set also include a warning about this:




        Setting a final field in this way is meaningful only during deserialization or reconstruction of instances of classes with blank final fields, before they are made available for access by other parts of a program. Use in any other context may have unpredictable effects, including cases in which other parts of a program continue to use the original value of this field.




        It seems that what we are witnessing here is the JIT taking advantage of the reordering and caching possibilities granted by the Language Specification.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 20 at 16:23

























        answered Nov 20 at 15:55









        Hulk

        2,39011434




        2,39011434
























            up vote
            4
            down vote













            It's because of the JIT optimization. To prove this, disable it using the following VM option:



            -Djava.compiler=NONE


            In this case all 10_000 iterations will work.



            Or, exclude the BasicHolder.getVALUE method from being compiled:



            -XX:CompileCommand=exclude,src/main/BasicHolder.getVALUE


            What actually happens under the hood is that after nth iteration, the hot method getVALUE is being compiled and static final Integer VALUE is being aggressively optimized (this is really the just-in-time constant1). From this point, the assertion starts to fail.



            The output of the -XX:+PrintCompilation with my comments:



            val 1       # System.out.println("val " + BasicHolder.getInstance().getVALUE());
            val 2
            val 3
            ...
            922 315 3 src.main.BasicHolder::getInstance (4 bytes) # Method compiled
            922 316 3 src.main.BasicHolder::getVALUE (4 bytes) # Method compiled
            ...
            val 1563 # after compilation
            val 1563
            val 1563
            val 1563
            ...




            1 - JVM Anatomy Park: Just-In-Time Constants.






            share|improve this answer























            • @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
              – Samy Elaiassi
              Nov 20 at 16:50















            up vote
            4
            down vote













            It's because of the JIT optimization. To prove this, disable it using the following VM option:



            -Djava.compiler=NONE


            In this case all 10_000 iterations will work.



            Or, exclude the BasicHolder.getVALUE method from being compiled:



            -XX:CompileCommand=exclude,src/main/BasicHolder.getVALUE


            What actually happens under the hood is that after nth iteration, the hot method getVALUE is being compiled and static final Integer VALUE is being aggressively optimized (this is really the just-in-time constant1). From this point, the assertion starts to fail.



            The output of the -XX:+PrintCompilation with my comments:



            val 1       # System.out.println("val " + BasicHolder.getInstance().getVALUE());
            val 2
            val 3
            ...
            922 315 3 src.main.BasicHolder::getInstance (4 bytes) # Method compiled
            922 316 3 src.main.BasicHolder::getVALUE (4 bytes) # Method compiled
            ...
            val 1563 # after compilation
            val 1563
            val 1563
            val 1563
            ...




            1 - JVM Anatomy Park: Just-In-Time Constants.






            share|improve this answer























            • @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
              – Samy Elaiassi
              Nov 20 at 16:50













            up vote
            4
            down vote










            up vote
            4
            down vote









            It's because of the JIT optimization. To prove this, disable it using the following VM option:



            -Djava.compiler=NONE


            In this case all 10_000 iterations will work.



            Or, exclude the BasicHolder.getVALUE method from being compiled:



            -XX:CompileCommand=exclude,src/main/BasicHolder.getVALUE


            What actually happens under the hood is that after nth iteration, the hot method getVALUE is being compiled and static final Integer VALUE is being aggressively optimized (this is really the just-in-time constant1). From this point, the assertion starts to fail.



            The output of the -XX:+PrintCompilation with my comments:



            val 1       # System.out.println("val " + BasicHolder.getInstance().getVALUE());
            val 2
            val 3
            ...
            922 315 3 src.main.BasicHolder::getInstance (4 bytes) # Method compiled
            922 316 3 src.main.BasicHolder::getVALUE (4 bytes) # Method compiled
            ...
            val 1563 # after compilation
            val 1563
            val 1563
            val 1563
            ...




            1 - JVM Anatomy Park: Just-In-Time Constants.






            share|improve this answer














            It's because of the JIT optimization. To prove this, disable it using the following VM option:



            -Djava.compiler=NONE


            In this case all 10_000 iterations will work.



            Or, exclude the BasicHolder.getVALUE method from being compiled:



            -XX:CompileCommand=exclude,src/main/BasicHolder.getVALUE


            What actually happens under the hood is that after nth iteration, the hot method getVALUE is being compiled and static final Integer VALUE is being aggressively optimized (this is really the just-in-time constant1). From this point, the assertion starts to fail.



            The output of the -XX:+PrintCompilation with my comments:



            val 1       # System.out.println("val " + BasicHolder.getInstance().getVALUE());
            val 2
            val 3
            ...
            922 315 3 src.main.BasicHolder::getInstance (4 bytes) # Method compiled
            922 316 3 src.main.BasicHolder::getVALUE (4 bytes) # Method compiled
            ...
            val 1563 # after compilation
            val 1563
            val 1563
            val 1563
            ...




            1 - JVM Anatomy Park: Just-In-Time Constants.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 20 at 21:22

























            answered Nov 20 at 16:19









            Oleksandr

            8,20543768




            8,20543768












            • @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
              – Samy Elaiassi
              Nov 20 at 16:50


















            • @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
              – Samy Elaiassi
              Nov 20 at 16:50
















            @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
            – Samy Elaiassi
            Nov 20 at 16:50




            @SotiriosDelimanolis "Correspondingly, compilers are allowed to keep the value of a final field cached in a register and not reload it from memory in situations where a non-final field would have to be reloaded." from the other answer, i think the JIL try to optimize after a bunch of access to the same final reference
            – Samy Elaiassi
            Nov 20 at 16:50


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.





            Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


            Please pay close attention to the following guidance:


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53395929%2fis-there-a-limit-to-overriding-final-static-field-with-reflection%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to change which sound is reproduced for terminal bell?

            Can I use Tabulator js library in my java Spring + Thymeleaf project?

            Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents