Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Spring Framework | Web Services | BioInformatics | Java Server Faces | Jboss 3.0 tutorial | Hibernate 3.0 | XML

Tutorial Categories: Ajax | Articles | JSP | Bioinformatics | Database | Free Books | Hibernate | J2EE | J2ME | Java | JavaScript | JDBC | JMS | Linux | MS Technology | PHP | RMI | Web-Services | Servlets | Struts | UML


 

Search Host

Monthly Fee($)
Disk Space (MB)
Register With us for Newsletter!
Visit Forum! Post Questions!
Jobs At RoseIndia.net!

Have tutorials?
Add your tutorial to our Java Resource and get tons of hits.

We offer free hosting for your tutorials. and exposure for thousands of readers. drop a mail
roseindia_net@yahoo.com
 
   

Tutorials

Java Server Pages

JAXB

Java Beans

JDBC

MySQL

Java Servlets

Struts

Bioinformatics

Java Code Examples

Interview Questions

 
Join For Newsletter

Powered by groups.yahoo.com
Visit Group! Post Questions!

Web Promotion

Web Submission

Submit Sites

Manual Submission?

Web Promotion Guide

Hosting Companies

Web Hosting Guide

Web Hosting

Linux

Beginner Guide to Linux Server

Frameworks

Persistence Framework

Web Frameworks

Free EAI Tools

Web Servers

Aspect Oriented Programming

Free Proxy Servers

Softwares

Adware & Spyware Remover

Open Source Softwares

Java 5 - "final" is not final anymore
   

       

2004-10-07 The Java Specialists' Newsletter [Issue 096] - Java 5 - "final" is not final anymore

Author: Dr. Heinz M. Kabutz

JDK version: Sun JDKs 1.5.0-rc, 1.4.2_05, 1.3.1_12, 1.2.2, 1.1.8

If you are reading this, and have not subscribed, please consider doing it now by going to our subscribe page. You can subscribe either via email or RSS.


Welcome to the 96th edition of The Java(tm) Specialists' Newsletter. We are slowly but surely approaching the 100th newsletter edition, which I am hoping to send on the 30th of November, our 4th anniversary of The Java(tm) Specialists' Newsletter.

In my last newsletter, I invited you to say "hello" with yahoo messenger. I had some interesting conversations since then with readers from around the world. I decided to rather not publish my yahoo ID on my website, imagine if 450'000 TheServerSide readers were to suddenly decide that they all wanted to be my friend ;-) So, my yahoo ID is special knowledge, reserved for my subscribers :)

The result of the survey was interesting. Of the 80+ emails that I received, about three quarters felt that generics would make Java code more maintainable. Due to Java 5 having just been released, none of them had started using generics in production code. Most of my customers are using JDK 1.4.2, some are on 1.4.1 and others still on 1.3.1. It will be at least another six months before some of them will start moving to Java 5.

Java 5 - "final" is not final anymore

Narve Saetre from Machina Networks in Norway sent me a note yesterday, mentioning that it was a pity that we could change the handle to a final array. I misunderstood him, and started patiently explaining that we could not make an array constant, and that there was no way of protecting the contents of an array. "No", said he, "we can change a final handle using reflection."

I tried Narve's sample code, and unbelievably, Java 5 allowed me to modify a final handle, even a handle to a primitive field! I knew that it used to be allowed at some point, but that it was then disallowed, so I ran some tests with older versions of Java. First, we need a class with 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 + " from " + country;
  }
}
  

JDK 1.1.x

In JDK 1.1.x, we were not able to access private fields using reflection. We could, however, create another Person with public fields, then compile our class against that, and swap the Person classes. There was no access checking at runtime if we were running against a different class to the one that we compiled against. However, we could not rebind final fields at runtime using either class swapping or reflection.

The JDK 1.1.8 JavaDocs for java.lang.reflect.Field had the following to say:

  • If this Field object enforces Java language access control, and the underlying field is inaccessible, the method throws an IllegalAccessException.
  • If the underlying field is final, the method throws an IllegalAccessException.
  • JDK 1.2.x

    In JDK 1.2.x, this changed a bit. We could now make private fields accessible with the setAccessible(true) method. Access of fields was now checked at runtime, so we could not use the class swapping trick to access private fields. However, we could now suddenly rebind final fields! Look at this 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 I ran this in JDK 1.2.2_014, I got the following result:

    
        Ng Keng Yap, 27 of IQ=110 from Malaysia
      

    Note, no exceptions, no complaints, and an incorrect IQ result. It seems that if we set a final field of a primitive at declaration time, the value is inlined, if the type is primitive or a String.

    JDK 1.3.x and 1.4.x

    In JDK 1.3.x, Sun tightened up the access a bit, and prevented us from modifying a final field with reflection. This was also the case with JDK 1.4.x. If we tried running the FinalFieldChange class to rebind the final fields at runtime using reflection, we would get:

    
        java version "1.3.1_12":
        Exception in thread "main" java.lang.IllegalAccessException: field is final
                at java.lang.reflect.Field.set(Native Method)
                at FinalFieldChange.change(FinalFieldChange.java:8)
                at FinalFieldChange.main(FinalFieldChange.java:12)
    
        java version "1.4.2_05"
        Exception in thread "main" java.lang.IllegalAccessException: Field is final
                at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:59)
                at java.lang.reflect.Field.set(Field.java:519)
                at FinalFieldChange.change(FinalFieldChange.java:8)
                at FinalFieldChange.main(FinalFieldChange.java:12)
      

    JDK 5.x

    Now we get to JDK 5.x. The FinalFieldChange class has the same output as in JDK 1.2.x:

    
        Ng Keng Yap, 27 of IQ=110 from Malaysia
      

    When Narve Saetre mailed me that he managed to change a final field in JDK 5 using reflection, I was hoping that a bug had crept into the JDK. However, we both felt that to be unlikely, especially such a fundamental bug. After some searching, I found the JSR-133: Java Memory Model and Thread Specification. Most of the specification is hard reading, and reminds me of my university days (I used to write like that ;-) However, JSR-133 is so important that it should be required reading for all Java programmers. (Good luck)

    Start with chapter 9 Final Field Semantics, on page 25. Specifically, read section 9.1.1 Post-Construction Modification of Final Fields. It makes sense to allow updates to final fields. For example, we could relax the requirement to have fields non-final in JDO.

    If we read section 9.1.1 carefully, we see that we should only modify final fields as part of our construction process. The use case is where we deserialize an object, and then once we have constructed the object, we initialise the final fields, before passing it on. Once we have made the object available to another thread, we should not change final fields using reflection. The result would not be predictable.

    It even says this: 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. This explains why our iq field stays the same, but country changes.

    Strangely, JDK 5 differs slightly from JDK 1.2.x, in that you cannot modify a static final field.

    import java.lang.reflect.Field;
    
    public class FinalStaticFieldChange {
      /** Static fields of type String or primitive would get 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 we run this with JDK 1.2.x and JDK 5.x, we get the following output:

    
        java version "1.2.2_014":
        stringValue = original value
        objValue = new Value
    
        java version "1.5.0"
        Exception in thread "main" java.lang.IllegalAccessException: Field is final
                at sun.reflect.UnsafeQualifiedStaticObjectFieldAccessorImpl.set(UnsafeQualifiedStaticObjectFieldAccessorImpl.java:59)
                at java.lang.reflect.Field.set(Field.java:656)
                at FinalStaticFieldChange.changeStaticField(FinalStaticFieldChange.java:12)
                at FinalStaticFieldChange.main(FinalStaticFieldChange.java:16)
      

    So, JDK 5 is like JDK 1.2.x, just different?

    Conclusion

    Do you know when JDK 1.3.0 was released? I struggled to find out, so I downloaded and installed it. The readme.txt file has the date 2000/06/02 13:10. So, it is more than 4 years old (goodness me, it feels like yesterday). JDK 1.3.0 was released several months before I started writing The Java(tm) Specialists' Newsletter! I think it would be safe to say that very few Java developers can remember the details of pre-JDK1.3.0. Ahh, nostalgia isn't what it used to be! Do you remember running Java for the first time and getting this error: "Unable to initialize threads: cannot find class java/lang/Thread"?

    I personally think it is risky to change something so fundamental to the language. I will read through that specification in detail to see what else has changed ...

    Gotta get some beauty sleep now - tomorrow I need to work on an access control system in Java for a client.

    Kind regards

    Heinz

    This material from The Java(tm) Specialists' Newsletter by Maximum Solutions (South Africa). Please contact Maximum Solutions for more information.

       

Useful Links
  JDO Tutorials
  EAI Articles
  Struts Tutorials
  Java Tutorials
  Java Certification

Tell A Friend
Your Friend Name
Search Tutorials

 

 
 
Browse all Java Tutorials
Java JSP Struts Servlets Hibernate XML
Ajax JDBC EJB MySQL JavaScript JSF
Maven2 Tutorial JEE5 Tutorial Java Threading Tutorial Photoshop Tutorials Linux Technology
Technology Revolutions Eclipse Spring Tutorial Bioinformatics Tutorials Tools SQL
 

Home | JSP | EJB | JDBC | Java Servlets | WAP  | Free JSP Hosting  | Search Engine | News Archive | Jboss 3.0 tutorial | Free Linux CD's | Forum | Blogs

About Us | Advertising On RoseIndia.net

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2007. All rights reserved.