interface - Why can final constants in Java be overridden? -


consider following interface in java:

public interface {     public final string key = "a"; } 

and following class:

public class implements {     public string key = "b";      public string getkey() {         return key;     } } 

why possible class come along , override interface i's final constant?

try yourself:

a = new a(); string s = a.getkey(); // returns "b"!!! 

despite fact shadowing variable it's quite interesting know can change final fields in java can read here:

java 5 - "final" not final anymore

narve saetre machina networks in norway sent me note yesterday, mentioning pity change handle final array. misunderstood him, , started patiently explaining not make array constant, , there no way of protecting contents of array. "no", said he, "we can change final handle using reflection."

i tried narve's sample code, , unbelievably, java 5 allowed me modify final handle, handle primitive field! knew used allowed @ point, disallowed, ran tests older versions of java. first, need class final fields:

public class person {   private final string name;   private final int age;   private final int iq = 110;   private final object country = "south africa";    public person(string name, int age) {     this.name = name;     this.age = age;   }    public string tostring() {     return name + ", " + age + " of iq=" + iq + " " + country;   } } 

jdk 1.1.x

in jdk 1.1.x, not able access private fields using reflection. could, however, create person public fields, compile our class against that, , swap person classes. there no access checking @ runtime if running against different class 1 compiled against. however, not rebind final fields @ runtime using either class swapping or reflection.

the jdk 1.1.8 javadocs java.lang.reflect.field had following say:

  • if field object enforces java language access control, , underlying field inaccessible, method throws illegalaccessexception.
  • if underlying field final, method throws illegalaccessexception.

jdk 1.2.x

in jdk 1.2.x, changed bit. make private fields accessible setaccessible(true) method. access of fields checked @ runtime, not use class swapping trick access private fields. however, rebind final fields! @ code:

import java.lang.reflect.field;  public class finalfieldchange {   private static void change(person p, string name, object value)       throws nosuchfieldexception, illegalaccessexception {     field firstnamefield = person.class.getdeclaredfield(name);     firstnamefield.setaccessible(true);     firstnamefield.set(p, value);   }   public static void main(string[] args) throws exception {     person heinz = new person("heinz kabutz", 32);     change(heinz, "name", "ng keng yap");     change(heinz, "age", new integer(27));     change(heinz, "iq", new integer(150));     change(heinz, "country", "malaysia");     system.out.println(heinz);   } } 

when ran in jdk 1.2.2_014, got following result:

ng keng yap, 27 of iq=110 malaysia    note, no exceptions, no complaints, , incorrect iq result. seems if set 

final field of primitive @ declaration time, value inlined, if type primitive or string.

jdk 1.3.x , 1.4.x

in jdk 1.3.x, sun tightened access bit, , prevented modifying final field reflection. case jdk 1.4.x. if tried running finalfieldchange class rebind final fields @ runtime using reflection, get:

java version "1.3.1_12": exception thread "main" illegalaccessexception: field final @ java.lang.reflect.field.set(native method) @ finalfieldchange.change(finalfieldchange.java:8) @ finalfieldchange.main(finalfieldchange.java:12)

java version "1.4.2_05" exception thread "main" illegalaccessexception: field final @ java.lang.reflect.field.set(field.java:519) @ finalfieldchange.change(finalfieldchange.java:8) @ finalfieldchange.main(finalfieldchange.java:12)

jdk 5.x

now jdk 5.x. finalfieldchange class has same output in jdk 1.2.x:

ng keng yap, 27 of iq=110 malaysia    when narve saetre mailed me managed change final field in jdk 5 using 

reflection, hoping bug had crept jdk. however, both felt unlikely, such fundamental bug. after searching, found jsr-133: java memory model , thread specification. of specification hard reading, , reminds me of university days (i used write ;-) however, jsr-133 important should required reading java programmers. (good luck)

start chapter 9 final field semantics, on page 25. specifically, read section 9.1.1 post-construction modification of final fields. makes sense allow updates final fields. example, relax requirement have fields non-final in jdo.

if read section 9.1.1 carefully, see should modify final fields part of our construction process. use case deserialize object, , once have constructed object, initialise final fields, before passing on. once have made object available thread, should not change final fields using reflection. result not predictable.

it says this: if final field initialized compile-time constant in field declaration, changes final field may not observed, since uses of final field replaced @ compile time compile-time constant. explains why our iq field stays same, country changes.

strangely, jdk 5 differs jdk 1.2.x, in cannot modify static final field.

import java.lang.reflect.field;  public class finalstaticfieldchange {   /** static fields of type string or primitive inlined */   private static final string stringvalue = "original value";   private static final object objvalue = stringvalue;    private static void changestaticfield(string name)       throws nosuchfieldexception, illegalaccessexception {     field statfinfield = finalstaticfieldchange.class.getdeclaredfield(name);     statfinfield.setaccessible(true);     statfinfield.set(null, "new value");   }    public static void main(string[] args) throws exception {     changestaticfield("stringvalue");     changestaticfield("objvalue");     system.out.println("stringvalue = " + stringvalue);     system.out.println("objvalue = " + objvalue);     system.out.println();   } } 

when run jdk 1.2.x , jdk 5.x, following output:

java version "1.2.2_014": stringvalue = original value objvalue = new value

java version "1.5.0" exception thread "main" illegalaccessexception: field final @ java.lang.reflect.field.set(field.java:656) @ finalstaticfieldchange.changestaticfield(12) @ finalstaticfieldchange.main(16)

so, jdk 5 jdk 1.2.x, different?

conclusion

do know when jdk 1.3.0 released? struggled find out, downloaded , installed it. readme.txt file has date 2000/06/02 13:10. so, more 4 years old (goodness me, feels yesterday). jdk 1.3.0 released several months before started writing java(tm) specialists' newsletter! think safe few java developers can remember details of pre-jdk1.3.0. ahh, nostalgia isn't used be! remember running java first time , getting error: "unable initialize threads: cannot find class java/lang/thread"?


Comments

Popular posts from this blog

c++ - How do I get a multi line tooltip in MFC -

asp.net - In javascript how to find the height and width -

c# - DataTable to EnumerableRowCollection -