tags:

views:

1068

answers:

8

From when I learned that the class java.lang.String is declared as final in Java, I was wondering why is that? I didn't find any answer back then, but this post: How to create a replica of String class in Java? reminded me of my query.

Sure, String provides all the functionality I ever needed, and never thought of any operation that would require an extension of class String, but still you'll never know what someone might need!

So, does anyone know what was the intent of the designers when they decided to make it final?

See also: Why is String a sealed class in C#?

+7  A: 

I believe it was for security purposes.

UPDATE: See http://renaud.waldura.com/doc/java/final-keyword.shtml for more detail (under Final Classes / For Security).

TrueWill
Thank you for the link! Really interesting...!
Alex
Since this is very close, so I'll just add a comment. The designers wanted to guarantee that the invariants of String could not be changed by a sub-class. To guarantee that String itself would not change they implemented parent delegation in class loaders (a different topic).
Kevin Brock
@Kevin - based on your comments, I think the community would be well served if you posted a separate answer.
TrueWill
+18  A: 

It is very useful to have strings implemented as immutable objects. You should read about immutability to understand more about it.

One advantage of immutable objects is that

You can share duplicates by pointing them to a single instance.

(from here).

If String were not final, you could create a subclass and have two strings that look alike when "seen as Strings", but that are actually different.

Bruno Reis
Unless there's a connection between final classes and immutable objects that I'm not seeing, I don't see how your answer relates to the question.
sepp2k
Because if it's not final you can pass a StringChild to some method as a String param, and it could be mutable (because a child class state change).
helios
Preventing subclasses prevents a mutable subclass.
Thilo
If String and its data members were not final, it could possibly be overridden by a derived class that adds mutability. Well, if the data members weren't also private. :)
shoover
And because you cannot override (being final) hashCode, intern and equal methods that are fundamental for all the class-library.
helios
Wow! Downvotes? Don't you understand how subclassing relates to immutability? I'd appreciate an explanation on what's the problem.
Bruno Reis
@Bruno, re: downvotes: I did not downvote you, but you could add a sentence as to how preventing subclasses enforces immutability. Right now, it is kind of a half-answer.
Thilo
@Bruno: I didn't downvote, but you really should point out, how subclassing relates to immutability in your answer for it to be relevant to the question.
sepp2k
@Thilo: I noticed that it was not true, which is why I deleted that comment.
sepp2k
+1  A: 

It may have been to simplify implementation. If you design a class that will be inheritable by users of the class, then you have a whole new set of use cases to consider into your design. What happens if they do this or that with X proptected field? Making it final they can focus on getting the public interface working correctly and make sure it's solid.

AaronLS
+1 for "designing for inheritance is hard". BTW, that's very nicely explained in Bloch's "Effective Java".
sleske
A: 

Also, because they are created in Java Heap where are other variable are not. So, in a way when you add something to it a new string is created and the earlier one is kept for garbage collection.

a String is allocated no different than any other object in Java.
Thilo
maybe I am wrong, but as you can't change the actual objects in Java you can't change the STring object. U can only point them to some new memory location!
Isn't everything on the heap in Java?
ntownsend
only objects! primitives ones are not.
+3  A: 

String is a very core class in Java, many things rely on it working a certain way, for example being immutable.

Making the class final prevents subclasses that could break these assumptions.

Note that, even now, if you use reflection, you can break Strings (change their value or hashcode). Reflection can be stopped with a security manager. If String was not final, everyone could do it.

Other classes that are not declared final allow you to define somewhat broken subclasses (you could have a List that adds to the wrong position, for example) but at least the JVM does not depend on those for its core operations.

Thilo
`final` on a class does not guarantee immutability. It just guarantees that a class's invariants (one of which can be immutability) cannot be changed by a sub-class.
Kevin Brock
@Kevin: yes. Final on a class guarantees that there are no subclasses. Has nothing to do with immutability.
Thilo
+1  A: 

As Bruno said it's about immutability. It's not only about Strings but as well about any wrappers e.g. Double, Integer, Character, etc. There are many reasons for this:

  • Thread safety
  • Security
  • Heap that is managed by Java itself (differently to ordinary heap that is Garbage Collected in different manner)
  • Memory management

Basically it so you, as a programmer, can be sure that your string will never be changed. It as well, if you know how it works, can improve memory managemnt. Try to create two identical string one after another, for example "hello". You will notice, if you debug, that they have identical IDs, that means that they are exactly THE SAME objects. This is due to the fact that Java let's you do it. This wouldn't be posssible if the strings were muttable. They can have the same I'd, etc., because they will never change. So if you ever decide to create 1,000,000 string "hello" what you'd really do is create 1,000,000 pointers to "hello". As well alling any function on string, or any wrappers for that reason, would result in creating another object (again look at object ID - it will change).

Aditionally final in Java does not necessarily mean that object cannot change (it is different to for example C++). It means that the address to which it points cannot change, but you still can change it's properties and/or attributes. So understanding the difference between immutability and final in some case might be really important.

HTH

References:

Artur
I do not believe that Strings go to a different heap or use a different memory management. They are certainly garbage collectable.
Thilo
Also, the final keyword on a class is completely different from the final keyword for a field.
Thilo
Okay, on Sun's JVM, Strings that are intern()ed may go into the perm-gen, which is not part of the heap. But that definitely does not happen for all Strings, or all JVM.
Thilo
Not all Strings go to that area, just the Strings that have been interned. Interning is automatic for literal Strings. (@Thilo, typing as you submitted your comment).
Kevin Brock
+10  A: 

This is a nice article that outlines two reasons already mentioned on the above answers:

  1. Security: the system can hand out sensitive bits of read-only information without worrying that they will be altered
  2. Performance: immutable data is very useful in making things thread-safe.

And this probably is the most detailed comment in that article. Its has to do with the string pool in Java and security issues. Its about how to decide what goes into the string pool. Assuming both strings are equal if their sequence of characters are the same, then we have a race condition on who gets there first and along with it security issues. If not, then the string pool will contain redundant strings thus losing the advantage of having it in the first place. Just read it out for yourself, will ya?


Extending String would play havoc with equals and intern. JavaDoc says equals:

Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.

Assuming java.lang.String wasn't final, a SafeString could equal a String, and vice versa; because they'd represent the same sequence of characters.

What would happen if you applied intern to a SafeString -- would the SafeString go into the JVM's string pool? The ClassLoader and all objects the SafeString held references to would then get locked in place for the lifetime of the JVM. You'd get a race condition about who could be the first to intern a sequence of characters -- maybe your SafeString would win, maybe a String, or maybe a SafeString loaded by a different classloader (thus a different class).

If you won the race into the pool, this would be a true singleton and people could access your whole environment (sandbox) through reflection and secretKey.intern().getClass().getClassLoader().

Or the JVM could block this hole by making sure that only concrete String objects (and no subclasses) were added to the pool.

If equals was implemented such that SafeString != String then SafeString.intern != String.intern, and SafeString would have to be added to the pool. The pool would then become a pool of <Class, String> instead of <String> and all you'd need to enter the pool would be a fresh classloader.

Anurag
A: 

The String class is the only class that has an "overloaded" operator, namely the + operator. Allowing programmers to subclass String, would allow them (and most likely tempt them) to do ugly hacks to exploit this:

class MyComplex extends String { ... }

MyComplex a = new MyComplex("5+3i");
MyComplex b = new MyComplex("7+4i");
MyComplex c = new MyComplex(a + b);   // works, since a and b are strings,
                                      // and a string + a string is a string.
aioobe