Skip to main content

Is Java String really immutable...?

In many texts String is cited as the ultimate benchmark of Java's various immutable classes. Well, I'm sure you'd have to think the other way once you have read this article.

To start with, let's get back to the books and read the definition of immutability. The Wikipedia defines it as follows -

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

I personally find this definition good as it mentions that an immutable instance's state should not be allowed to be modified after it's construction.

Now keeping this in the back of our minds, let's decompile Java's standard String implementation and peep into the 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;
}

A detailed look at the above code reveals this to be a classic implementation of the 'lazy evaluation' pattern; i.e. the String class instead of computing the hash value [1] during an instance's construction or [2] computing it each time the hashCode() method is called; computes it once, i.e. on the first call to hashCode(), and saves the computed value in the hash attribute.

Now, here is a test to prove the above quoted statement -

String string = "MyDearString";

Field field = String.class.getDeclaredField("hash");
field.setAccessible(true);

System.out.println("Before: " + field.getInt(string));

string.hashCode();

System.out.println("After: " + field.getInt(string ));

Anxious to know what the output would looks like? Here it is...

Before: 0
After: -1554135584

So this infers that for a given String instance which we create, but for which we never call hashCode(), the private hash field will remain to be zero. It is only changed when we call hashCode().

Well, don't you find this in contrast with the basic definition of an object's immutability?

One might argue that we can not observe a String instance in a different state without 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.

Well, if one doesn't observe a change does that mean it never happened...?

This reminds me about the other day when i scratched my new car, from below, against an irregular speed-breaker and my friend Manish said that I should not be worried about that because if a scratch is not visible its never been there. Well, is it really never there...?

However it seems like String is not immutable. Although it seems safe, ignoring reflective access, it definitely looks incorrect.

Post me your views around this...

Comments

vivi said…
The private field "hash" does not hold any state information, it is merely a cache of the hashCode() return value. No method return value or behavior will be affected by the fact that hash is set or not.
Also, using reflection to access private fields is a bit cheating ;-)
Rahul Roy said…
Hi, thanks for sharing your views. I do agree that using reflection here in this case is a cheat. However, it does make one thing clear here, i.e. the Java String is just not a perfect immutable class, going as per the core definition of it. :) Ideally, if one states a class to be immutable then, no matter what, it's state (even that of private attributes) should not be changed/altered after its once constructed.

Popular posts from this blog

Shard – A Database Design

Scaling Database is one of the most common and important issue that every business confronts in order to accommodate the growing business and thus caused exponential data storage and availability demand. There two principle approaches to accomplish database scaling; v.i.z. vertical and horizontal. Regardless of which ever scaling strategy one decides to follow, we usual land-up buying ever bigger, faster, and more expensive machines; to either move the database on them for vertical scale-up or cluster them together to scale horizontally. While this arrangement is great if one has ample financial support, it doesn't work so well for the bank accounts of some of our heroic system builders who need to scale well past what they can afford. In this write-up, I intend to explain a revolutionary and fairly new database architecture; termed as Sharding, that some websites like Friendster and Flickr have been using since quite sometime now. The concept defines an affordable approach t...

FAINT - Search for faces

Lately, I've been playing around a bit with facial pattern recognition algorithms and their open source implementations. I came across many reference implementation but a very few were implemented in Java, and the Eigenfaces algorithm by far happens to be the best amongst them all. During my research around the said topic i happened to stumble-upon an implementation called FAINT (The Face Annotation Interface - http://faint.sourceforge.net). Faint by far the best facial pattern recognition API and as you must have already guessed, it implements the Eigenfaces algorithm. Now enough of theory talks, how about implementing an example with faint...? Here is one for all you face-recognition enthusiasts. The following example simply searches for faces in a given photograph and thumbnails them. Now, I know thats not face recognition; but be a little creative here. Once you have the facial thumbnails extracted, its never a big deal to look further in the Faint API and find methods which ca...