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
Post a Comment