Why is the String class declared final in Java?

86,608

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:

  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.

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:

Share:
86,608
Alex Ntousias
Author by

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, 2020

Comments

  • Alex Ntousias
    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
    sepp2k over 14 years
    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.
  • helios
    helios over 14 years
    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).
  • hansvb
    hansvb over 14 years
    Preventing subclasses prevents a mutable subclass.
  • Simo Erkinheimo
    Simo Erkinheimo over 14 years
    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. :)
  • helios
    helios over 14 years
    And because you cannot override (being final) hashCode, intern and equal methods that are fundamental for all the class-library.
  • Bruno Reis
    Bruno Reis over 14 years
    Wow! Downvotes? Don't you understand how subclassing relates to immutability? I'd appreciate an explanation on what's the problem.
  • hansvb
    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
    hansvb over 14 years
    I do not believe that Strings go to a different heap or use a different memory management. They are certainly garbage collectable.
  • hansvb
    hansvb over 14 years
    Also, the final keyword on a class is completely different from the final keyword for a field.
  • sepp2k
    sepp2k over 14 years
    @Thilo: I noticed that it was not true, which is why I deleted that comment.
  • hansvb
    hansvb over 14 years
    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.
  • Kevin Brock
    Kevin Brock over 14 years
    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
    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
    hansvb over 14 years
    @Kevin: yes. Final on a class guarantees that there are no subclasses. Has nothing to do with immutability.
  • sleske
    sleske about 14 years
    +1 for "designing for inheritance is hard". BTW, that's very nicely explained in Bloch's "Effective Java".
  • Jay
    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
    Jay over 13 years
    Making 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
    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
    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
    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
    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
    Alderath about 12 years
    Couldn'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
    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
    Suresh Sharma about 11 years
    Thanks 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
    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
    Georgie over 10 years
    In 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
    Paolo about 10 years
    StringBuilder is final too, so being immutable is not necessarly the reason
  • Bruno Reis
    Bruno Reis about 10 years
    @Paolo: being final is only one of the prerequisites for a class to be immutable.
  • Stephan Eggermont
    Stephan Eggermont over 8 years
    Of 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
    Marko Popovic over 8 years
    Please clarify your answer.
  • Abhishek Singh
    Abhishek Singh over 7 years
    Some 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
    shitpoet over 5 years
    But isn't making all fields final enough to make String behave as it is intended to? As I understand, final fields can not be overridden in Java.
  • Tachi
    Tachi about 2 years
    It is not clear to me how making String final would improve security. Could you please expand on that?