Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why String class is immutable even though it has a non -final field called "hash"

I was reading through Item 15 of Effective Java by Joshua Bloch. Inside Item 15 which speaks about 'minimizing mutability' he mentions five rules to make objects immutable. One of them is is to make all fields final . Here is the rule :

Make all fields final : This clearly expresses your intent in a manner that is enforced by the system. Also, it is necessary to ensure correct behavior if a reference to a newly created instance is passed from one thread to another without synchronization, as spelled out in the memory model [JLS, 17.5; Goetz06 16].

I know that String class is an example of a immutable class. Going through the source code I see that it actually has a hash instance which is not final .

//Cache the hash code for the string
private int hash; // Default to 0

How does String become immutable then ?

like image 607
Inquisitive Avatar asked Jul 01 '12 13:07

Inquisitive


2 Answers

The remark explains why this is not final:

//Cache the hash code for the string

It's a cache. If you don't call hashCode, the value for it will not be set. It could have been set during the creation of the string, but that would mean longer creation time, for a feature you might not need (hash code). On the other hand, it would be wasteful to calculate the hash each time its asked, give the string is immutable, and the hash code will never change.

The fact that there's a non-final field does somewhat contradict that definition you quote, but here it's not part of the object's interface. It's merely an internal implementation detail, which has no effect on the mutability of the string (as a characters container).

Edit - due to popular demand, completing my answer: although hash is not directly part of the public interface, it could have affected the behavior of that interface, as hashCode return its value. Now, since hashCode is not synchronized, it is possible that hash be set more than once, if more than one thread used that method concurrently. However, the value that is set to hash is always the result of a stable calculation, which relies only on final fields (value, offset and count). Therefore, every calculation of the hash yield the exact same result. For an external user, this is just as if hash was calculated once - and just as if it was calculated each and every time, as the contract of hashCode requires that it consistently returns the same result for a given value. Bottom line, even though hash is not final, its mutability is never visible to an external viewer, hence the class can be considered immutable.

like image 137
eran Avatar answered Oct 15 '22 02:10

eran


String is immutable because as far as its users are concerned, it can never be modified and will always look the same to all threads.

hashCode() is computed using the racy single-check idiom (EJ item 71), and it's safe because it doesn't hurt anybody if hashCode() is computed more than once accidentally.

Making all fields final is the easiest and simplest way to make classes immutable, but it's not strictly required. So long as all methods return the same thing no matter which thread calls it when, the class is immutable.

like image 9
Louis Wasserman Avatar answered Oct 15 '22 00:10

Louis Wasserman