You make an object immutable if you don't want the behavior of the object to be changed by anyone. String is made immutable in order to standardize its behavior. To make an object immutable you should declare its class as final.
If a class is immutable, then once an instance is created, the data held by that instance does not change. If you want to "change" the data in an immutable class, you generally need to create a new object, with the new data.
Immutability has several advantages:
1. Thread safety. If you're using multiple threads, immutable objects are inherently safe for all threads to use. They won't change values for reasons you can't see. If you ever have a problem with threads accessing data in an unsafe manner, it's usually a major pain to debug. Anything that avoids this is Good™.
2. Simplicity. Even if you're not using multiple threads, immutable objects are often simpler to understand. If you pass a reference to a MyImmutableObject instance to some code written by someone else, you generally don't have to worry about whether or not that outside code is going to change your object. It won't. When analyzing new code, immutable objects are your friend - they mean there's one less thing for you to keep track of.
3. Memory savings. If you know that the data in a given instance will never change, you can save both memory and time by re-using an existing object rather than creating a new object with data identical to an old object. You couldn't do this if there were a possibility that someone would want to change the data in the new object, because you wouldn't want the old object's data to change.
I think the first two are most important. The first is critical if you're using multiple threads, while the second is more important if you're using only one thread (or more generally, using data manipulated by only one thread). But beware that multi-threading is becoming more and more ubiquitous, and you may well be using multiple threads even if you don't realize it. The third reason is not so important, most of the time. But it can be handy in some cases. And it's used extensively within the Java compiler and JVM - all identical String constants refer to the same instance, by design.
In addition to what Mike said, there can be serious problems with the use of HashMap and HashSet (and similar structures) if the hashCode() is calculated from the value of the member variables (which is typical) if they are allowed to change.
Its fairly easy to create an object of your class, say Student, and put it in a HashSet, and then change the Student's name, say to fix a typo or because she got married. That changes the hashCode() and now you can't find the instance in the map.
Joined: Nov 20, 2008
there can be serious problems with the use of HashMap and HashSet (and similar structures) if the hashCode() is calculated from the value of the member variables (which is typical) if they are allowed to change.
Thanks Mike and Pat...
Pat i didn't get the HashMap and Set usage... Some where i read as "make good Map keys and Set elements (these objects must not change state while in the collection) " Please explain me in detail....
When you insert an object into a HashMap or HashSet, it is put inside something called a "bucket". The hashCode() determines in which bucket the object is stored.
Now when retrieving, the HashMap / HashSet first determines in which bucket to check using hashCode(). Then it iterates over all elements in that bucket (so a much smaller number of items) and uses equals(Object) to determine equality.
Now if hashCode() returns value X when you insert the object, but then returns value Y (with X != Y) when you try to retrieve it, then the HashMap / HashSet will look in the wrong bucket and never find the object again. You can trust me on this - I've tried it as an exercise a while ago.
TreeMap / TreeSet have the same issue but then the results of compareTo.
Think of buckets as file drawers. you have you 'a' drawer, you're 'b' drawer, etc. beyond that, you don't care too much, so you just stick it anywhere in the drawer. When you want to find it, you just go to the right drawer and read all the file names until you find the right one.
Now, you want to put a student's file into your filing cabinet. So you look at the first letter of their last name - in this case, "Posenberger" goes into the 'P' drawer.
Now someone comes along and sees the name is spelled wrong, and corrects it on the document to "Rosenberger". They print it out, and you want to file it again. So, you look for any file in the 'R' drawer, and guess what? it's not there. you will never find the original file.
The Hash function does the same sort of "which drawer should I look in" computation (only in a more complicated way to allow for more 'buckets'). Strings are commonly used as the 'key' for the has. "Rosenberger" will always compute to the same value. If we allow this string to change, then the Hash value will (almost without a doubt) change, so you'll loose where you put things.
There are only two hard things in computer science: cache invalidation, naming things, and off-by-one errors