AMD Logo AMD Developer Central
AMD Developer Blogs
AMD Developer Blogs - Is String Immutable?
Decrease font size
Increase font size
March 3, 2009
  Is String Immutable?

In many texts String is cited as the 'gold standard' of Java's various immutable classes.  Any google of 'Immutable Java' will invariably reveal examples using String to demonstrate the benefits and characteristics of a good immutable class.  

 

From Wikipedia(http://en.wikipedia.org/wiki/Immutable_object) we get the following definition:-

 'In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created.'

I like this definition as it describes what I had assumed to be the main point: that an instance's state should not be allowed to be modified post-construction.

 

However, I recently found myself looking at the String class and came across its hashCode() method :-

public int hashCode() {
 int h = hash; 
 if (h == 0) {
     int off = offset;
     char val[] = value;
     int len = count;
       for (int i = 0; i < len; i++) {
           h = 31*h + val[off++];
       }
      
hash = h;
    }
    return h;
}

Looking closely we see that this is a classic implementation of the 'lazy evaluation' pattern. Rather than computing the hash value in the constructor, or computing it each time the hashCode() method is called,we compute it once (on the first call to hashCode()) and save the computed value in the hash field.

 

We can see this if we read the private hash field reflectively.

String helloWorld = "helloWorld";

Field field=String.class.getDeclaredField("hash");
field.setAccessible(true); // because hash field is private

System.out.println("Before first hashcode call "+field.getInt(helloWorld));

helloWorld.hashCode();

System.out.println("After first hashcode call "+field.getInt(helloWorld));

If one runs this snippet of code it will output something like


Before first hashcode call 0
After first hashcode call -1554135584

 

So for a String instance which we create, but for which we never call hashCode(), the private hash field will remain 0. It is only changed when we call hashCode().

 

By Wikipedia's definition I believe String fails the immutablility test.

 

The argument might be that we can't observe a String instance in a different state without resorting to a reflective read of String's hash field and because the call to retrieve the state actually modifies it; if we can't observe it changing, then it didn't change.

 

This is reminiscent of

 

"If a tree falls in a forest and nobody hears it, did it make a noise?"

 

Or my personal version

 

"If I say something in a room and my wife doesn't hear me, am I still wrong?"

 

However it still seems like String is not immutable.

 

In Eric Lippert's blog (http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx) he refers to this as 'Popsicle Immutability' and although it seems safe, (ignoring reflective access) it does seem incorrect.

 

So I would like to open up a discussion:  Is String immutable?



-------------------------

The information presented in this document is for informational purposes only and may contain technical inaccuracies, omissions and typographical errors. Links to third party sites are for convenience only, and no endorsement is implied


 Post a Comment    

    Posted By: Gary Frost @ 03/03/2009 10:44 AM     AMD Java Labs  

March 12, 2009

Comments


 

"an immutable object is an object whose state cannot be modified after it is created"

Yes, string is immutable, because 'hash' instance variable is not part of it's state. I'm quite sure that there is somewhere a definition of the state which will tell that it either has to be observable or modify the behaviour of the object. Hash does neither.

Another example which you may find similar. Imagine an immutable object, which increments public static variable each time it's method is called. Again, this variable is not part of the state of the object, so object is immutable.

Now, if you REALLY want to split hairs, hash IS changing the state of object in certain way - it makes hashCode method faster. You could observe this change if you really want, thus having slow-hash-String and fast-hash-String states. And you could go into identity hashcode modifying second word of object in memory when called for the first time... observe speed of locking depending on fact if it was locked by given thread before or not, or if identity hashcode was created or not...

Yes, String is immutable for all sane meanings of this word.


 Posted By: Artur Biesiadowski @ 03/12/2009 03:05 PM   :  Post a reply

March 24, 2009
 

by hashcode() reasoning....  all immutable objects in java fails the wikipedia definition.

but if we consider that by using exposed apis an object's state is not changed then String does qualify as immutable from developer's perspective.

 

 


 Posted By: amit goel @ 03/24/2009 01:52 AM   :  Post a reply

April 15, 2009
 

Well ... prove its mutable by changing the string value with regular basic language code and you will prove it's not immutable ;-)

An offtopic comment, but still about Java : why processors manufacturers do not have build-in optimizer for Java's bytecode as this technology is out since a decade ? Taking aside ARM (with Jazelle™), because their IP level constraints make it useless at this time to integrators ... To be more precise, there are two things that would be great to get on a CPU : direct java bytecode execution (actually a CPU translation to its internal instructions set) and an automatic memory management mechanism = a silicon handled garbage collection. What is your tought ?

This would be a big hit at enterprise market ;-)



Edited: 04/15/2009 at 10:44 AM by AMD Developer Blogs Moderator

 Posted By: Test Man @ 04/15/2009 09:14 AM   :  Post a reply

April 20, 2009
 
Thanks for your comment.
With any potential features, processor manufacturers have to weigh the benefits of enabling those in hardware, relying on components of the software stack, or some combination of the two.  
With your example of bytecode optimization, the JVM compiler does a very good job generating native x86/x64 code from bytecode for AMD systems.  And it keeps getting better, because we keep adding more optimizations with every JRE release through our close technology partnerships with the major JRE vendors.  All you have to do is pick up a new Java runtime and you'll get those benefits.  By the way, via collaboration with the Sun Hotspot team, those optimizations amount to a 220% performance improvement from JDK 5.0_04 to Java 6.0_05p.  See slide 5 of this Sun Tech Days presentation for details.   That's a strong reason for doing this in the software stack.
Because of the trade-offs with enablement of features in the hw, AMD's focus has been to put functionality in the processor that assists the software components, including the JRE, to do a wider range of optimizations.  See our Light-Weight Profiling (LWP) proposal, for example.
The same can be said of garbage collection.  GC latency has been greatly improved over the years, and will continue to do so with JDK7's G1 collector.  So, handling it all in silicon is probably not necessary.  However, I could see having some level of hardware assist via instructions that would reduce that latency further.
What are your thoughts about this balanced hw/sw approach?


-------------------------

The information presented in this document is for informational purposes only and may contain technical inaccuracies, omissions and typographical errors. Links to third party sites are for convenience only, and no endorsement is implied.


 Posted By: Ben Pollan @ 04/20/2009 11:25 AM   :  Post a reply

FuseTalk Hosting Executive Plan - © 1999-2009 FuseTalk Inc. All rights reserved.

Contact AMD | Terms and Conditions | Forum Rules | ©2009 Advanced Micro Devices, Inc. | Privacy | Trademark information