Modifying final fields in Java

前端 未结 5 2018
故里飘歌
故里飘歌 2020-12-13 00:07

Let\'s start with a simple test case:

import java.lang.reflect.Field;

public class Test {
  private final int primitiveInt = 42;
  private final Integer wra         


        
5条回答
  •  长情又很酷
    2020-12-13 00:13

    Reflection's set(..) method works with FieldAccessors.

    For int it gets an UnsafeQualifiedIntegerFieldAccessorImpl, whose superclass defines the readOnly property to be true only if the field is both static and final

    So to first answer the unasked question - here's why the final is changed without exception.

    All subclasses of UnsafeQualifiedFieldAccessor use the sun.misc.Unsafe class to get the values. The methods there are all native, but their names are getVolatileInt(..) and getInt(..) (getVolatileObject(..) and getObject(..) respectively). The aforementioned accessors use the "volatile" version. Here's what happens if we add the non-volatile version:

    System.out.println("reflection: non-volatile primitiveInt = "
         unsafe.getInt(test, (long) unsafe.fieldOffset(getField("primitiveInt"))));
    

    (where unsafe is instantiated by reflection - it is not allowed otherwise) (and I call getObject for Integer and String)

    That gives some interesting results:

    reflection: primitiveInt = 84
    direct: primitiveInt = 42
    reflection: non-volatile primitiveInt = 84
    reflection: wrappedInt = 84
    direct: wrappedInt = 84
    reflection: non-volatile wrappedInt = 84
    reflection: stringValue = 84
    direct: stringValue = 42
    reflection: non-volatile stringValue = 84
    

    At this point I recall an article at javaspecialists.eu discussing an related matter. It quotes JSR-133:

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

    Chapter 9 discusses the details observed in this question.

    And it turns out this behaviour is not that unexpected, since modifications of final fields are supposed to happen only right after initialization of the object.

提交回复
热议问题