October 10, 2009

Could we have a discussion on why String is Immutable?

Not changeable. All Java variables are by default mutable. You can make them immutable by using the final keyword. You can also make them private and provide no accessors to the outside world to change them. The wrapper classes, Byte, Character, Short, Integer, Long, Float and Double are all immutable. Strings are immutable. StringBuffers are mutable. The only way to change the value of the number inside the object wrapper is to create a new object and point to that instead

Strings are value objects. Value objects should always be immutable. If you
want a different value (different String), you need a different object.

Apart from that, javac was/is written in Java
. javac needed to be reasonably
performing. Parsing Java source code
involves the generation and
manipulation of lots of Strings *and* StringBuffers. The two classes have
some optimization-driven "incestuous" relationship behind the scenes which
relies on the immutability aspect.

I'm guessing that back in 93-94-95, such concerns were strong enough to make
String immutable simply for those reasons.

> I understand that making String immutable, makes it thread safe and
> thus imporves performance.
>
> Is there any other reason for making it Immutable?

Roedy hinted at one, but let me explain further. Java has this thing
called a SecurityManager, and it is responsible for checking that
unprivileged code (for example, an applet) is allowed to do stuff. To
pick one example, applets are typically allowed to contact their server

of origin with sockets, but not other servers. So let's say I write
this:

String hostName = "my.origin.server.com";
Socket s = new Socket(hostName, 1234);

Looks fine. In the second line, the SecurityManager will first check to
be sure that "my.origin.server.com" really is the origin server. Then
it will establish a connection to that server. BUT this only works if
the server name can't change between the security check and establishing
the connection. If String were not immutable, I could do this:

String fakeHostName = "my.origin.server.com";
String realHostName = "evil.server.com";

String hostName = new String(fakeHostName);

new Thread() {
public void run()
{
while (true)
{
hostName.mutateTo(realHostName);
hostName.mutateTo(fakeHostName);
}
}
}.start();

boolean success = false;
while (!success)
{
try
{
Socket s = new Socket(hostName, 1234);
// try talking to evil.server.com

success = true;
}
catch (SecurityException e) { }
}

It might take a while, but eventually, a context switch would happen
between the security check and establishing the connection. When that
happens, security is compromised.

See how that works? It's not impossible to code around, but if String
were mutable it would be a lot bigger pain to write methods that make
proper use of java.security.AccessController.doPrivileged.

No comments:

Post a Comment

I'm certainly not an expert, but I'll try my hardest to explain what I do know and research what I don't know.

My Favorite Site's List

#update below script more than 500 posts