Why is the String class declared final in Java?
Solution 1
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.
Solution 2
This is a nice article that outlines two reasons already mentioned on the above answers:
- Security: the system can hand out sensitive bits of read-only information without worrying that they will be altered
- 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.
Solution 3
The absolutely most important reason that String is immutable or final is that it is used by the class loading mechanism, and thus have profound and fundamental security aspects.
Had String been mutable or not final, a request to load "java.io.Writer" could have been changed to load "mil.vogoon.DiskErasingWriter"
reference : Why String is immutable in Java
Solution 4
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.
Solution 5
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:
Alex Ntousias
By day: Software and Distributed Systems Engineer Consultant By night: Love experimenting with new technologies and work on personal projects.
Updated on March 21, 2020Comments
-
Alex Ntousias over 4 years
From when I learned that the class
java.lang.String
is declared as final in Java, I was wondering why that is. 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 I 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 the intent of the designers was when they decided to make it final?
-
sepp2k over 14 yearsUnless 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.
-
helios over 14 yearsBecause 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).
-
hansvb over 14 yearsPreventing subclasses prevents a mutable subclass.
-
Simo Erkinheimo over 14 yearsIf 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. :)
-
helios over 14 yearsAnd because you cannot override (being final) hashCode, intern and equal methods that are fundamental for all the class-library.
-
Bruno Reis over 14 yearsWow! Downvotes? Don't you understand how subclassing relates to immutability? I'd appreciate an explanation on what's the problem.
-
hansvb over 14 years@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.
-
hansvb over 14 yearsI do not believe that Strings go to a different heap or use a different memory management. They are certainly garbage collectable.
-
hansvb over 14 yearsAlso, the final keyword on a class is completely different from the final keyword for a field.
-
sepp2k over 14 years@Thilo: I noticed that it was not true, which is why I deleted that comment.
-
hansvb over 14 yearsOkay, 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.
-
Kevin Brock over 14 yearsNot 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 over 14 years
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. -
hansvb over 14 years@Kevin: yes. Final on a class guarantees that there are no subclasses. Has nothing to do with immutability.
-
sleske about 14 years+1 for "designing for inheritance is hard". BTW, that's very nicely explained in Bloch's "Effective Java".
-
Jay over 13 years@shoover: The private tags would make it more awkward to break, but not impossible. A subclass could add its own fields, and then refer to these fields in overriden versions of functions. It would be crazy, but you could do it. I've certainly seen crazier code.
-
Jay over 13 yearsMaking a class final does not, of itself, make it immuatable. But making an immutable class final insures that no one makes a subclass that breaks immutability. Perhaps the people making the point about immutability were unclear in exactly what they meant, but their statements are correct when understood in context.
-
Bruno Reis over 13 years@Jay: wow, this is old. But anyways, we are not talking about hacking, or preventing it. If you can run a process on a machine, you can potentially read (an modify) any part of its memory, including private members of an object inside a virtual machine. This is all about software engineering, where we try to reduce complexity by hiding (encapsulating) information. One way to reduce complexity is to be sure that an object won't ever change its state -- immutability.
-
Bruno Reis over 13 years@Jay: so: "private" is not related to security at all, it's related to reduction of complexity. As an illustration, many times when you compile a class in Scala, some of its protected members may be written as "public" on the
.class
file! The Scala compiler, however, will add some metadata to the class that disallow other Scala classes to access these members. -
Jay over 13 years@Bruno: RE "wow this is old": I saw the "Jan 15" and was thinking this was 2 weeks old. I didn't look at the year.
-
Jay over 13 years@Bruno: But to the point, yes, I wasn't talking about security either, but rather about really dumb coding techniques. Shoover made a comment that implied that making the data private would prevent a subclass from making a String mutable. The intent of my post was that the privates make it harder for someone to do this, but not impossible. I am not recommending this, quite the contrary I'm saying it would be a really bad idea. I don't think you and I are disagreeing. I was just commenting on a detail point.
-
Alderath about 12 yearsCouldn't this problem be solved by simply adding a javadoc comment to the String class, saying "Any class extending the String class MUST be immutable", instead of preventing inheritance through the final keyword?
-
Bruno Reis about 12 years@Alderath: even if you could believe that every developer would strictly obey that rule, why do you think it would be useful?
-
Suresh Sharma about 11 yearsThanks for this reply its very useful. we've two facts now. A String is a Final class & its immutable because it can't be changed but can be referred to another object. but what about:- String a = new String("test1"); then, s = "test2"; If String is Final class object then how can it be modified ? How can i use modified final object. Please let me if i wrongly asked anything.
-
Chance about 11 years@BrunoReis - found a nice article you could link to that has an interview with James Gosling (creator of Java) where he briefly talks about this topic here. Here's an interesting snippet: "One of the things that forced Strings to be immutable was security. You have a file open method. You pass a String to it. And then it's doing all kind of authentication checks before it gets around to doing the OS call. If you manage to do something that effectively mutated the String, after the security check and before the OS call, then boom, you're in..."
-
Georgie over 10 yearsIn my opinion String never behaves like a primitive type. A string literal like "java" is actually an object of the String class (you can use the dot operator on it, immediately following the closing quote). So assigning a literal to a string variable is just assigning object references as usual. What is different is that the String class has language-level support built into the compiler... turning things in double quotes into String objects, and the + operator as mentioned above.
-
Paolo about 10 yearsStringBuilder is final too, so being immutable is not necessarly the reason
-
Bruno Reis about 10 years@Paolo: being final is only one of the prerequisites for a class to be immutable.
-
Stephan Eggermont over 8 yearsOf course the performance reason is a fallacy: had String been an interface I would have been able to provide an implementation that performs better in my application.
-
Marko Popovic over 8 yearsPlease clarify your answer.
-
Abhishek Singh over 7 yearsSome times back I read this answer and I thought that's an okey answer, then I read hashcode & equals from 'The Effective Java' and realized that's a very good answer. Anyone needs explanations, I recommend ieam 8 & iteam 9 of the same book.
-
shitpoet over 5 yearsBut isn't making all fields
final
enough to makeString
behave as it is intended to? As I understand,final
fields can not be overridden in Java. -
Tachi about 2 yearsIt is not clear to me how making String final would improve security. Could you please expand on that?