Why is the String class declared final in Java?
Asked Answered
T

16

148

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?

Theatrics answered 15/1, 2010 at 1:15 Comment(7)
Thank you all for your answers, especially TrueWill, Bruno Reis and Thilo! I wish I could pick more than one answer as the best one, but unfortunately...!Theatrics
Also consider the proliferation of "Oh I just need a few more utilty methods on String" projects which would pop up - all of which could not use each others Strings because they were a different class.Maseru
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.Pondweed
You can view this good article.Risner
One thing we have thankfully avoided in Java is the "everybody has their own subclass of String with a lot of extra methods, and none of these are compatible with each other".Maseru
best link javarevisited.blogspot.com/2010/10/…Ormolu
@Premraj, thanks for your reference to the link. But after reading this write-up in depth, it seems immutable and Final are exactly the same. My question here is - are immutable and Final are one & the same? If not then the mentioned link does not explicitly elaborate on 'why String is Final?' and pls help me understand this.Westmoreland
C
92

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.

Caporetto answered 15/1, 2010 at 1:17 Comment(19)
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.Jolenejolenta
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).Lorca
Preventing subclasses prevents a mutable subclass.Newmarket
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. :)Hittel
And because you cannot override (being final) hashCode, intern and equal methods that are fundamental for all the class-library.Lorca
Wow! Downvotes? Don't you understand how subclassing relates to immutability? I'd appreciate an explanation on what's the problem.Caporetto
@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.Newmarket
@Thilo: I noticed that it was not true, which is why I deleted that comment.Jolenejolenta
@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.Diplomat
@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.Caporetto
@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.Caporetto
@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.Diplomat
@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.Diplomat
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?Nugent
@Alderath: even if you could believe that every developer would strictly obey that rule, why do you think it would be useful?Caporetto
@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..."Luganda
StringBuilder is final too, so being immutable is not necessarly the reasonLudvig
@Paolo: being final is only one of the prerequisites for a class to be immutable.Caporetto
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.Buskus
L
61

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.

Luganda answered 15/1, 2010 at 2:14 Comment(2)
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.Centi
It is not clear to me how making String final would improve security. Could you please expand on that?Roque
E
28

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

Ecclesiasticus answered 21/5, 2011 at 3:55 Comment(0)
N
17

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.

Newmarket answered 15/1, 2010 at 1:23 Comment(4)
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.Costumer
@Kevin: yes. Final on a class guarantees that there are no subclasses. Has nothing to do with immutability.Newmarket
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.Diplomat
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.Recourse
G
6

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:

Grouper answered 15/1, 2010 at 1:36 Comment(5)
I do not believe that Strings go to a different heap or use a different memory management. They are certainly garbage collectable.Newmarket
Also, the final keyword on a class is completely different from the final keyword for a field.Newmarket
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.Newmarket
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).Costumer
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.Pondweed
C
3

To make sure we do not get a better implementation. It should of course have been an interface.

[edit] Ah, getting more clueless down votes. The answer is perfectly serious. I've had to program my way around the stupid String implementation several times, leading to severe performance & productivity loss

Centi answered 7/3, 2011 at 21:45 Comment(0)
R
3

Apart from the obvious reasons suggested in other answers, one thought of making String class final could also be related to virtual methods performance overhead. Remember String is a heavy class, making this final, means no sub-implementation for sure, means no indirection calling overhead ever. Of course now we have things like virtual invoke and others, which always does these kind of optimization for you.

Recourse answered 20/8, 2015 at 13:3 Comment(0)
J
2

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.

Juliettajuliette answered 15/1, 2010 at 1:19 Comment(1)
+1 for "designing for inheritance is hard". BTW, that's very nicely explained in Bloch's "Effective Java".Teresetereshkova
H
2

In addition to the reasons mentioned in other answers (security, immutability, performance) it should be noted that String has special language support. You can write String literals and there's support for the + operator. Allowing programmers to subclass String, would encourage hacks such as:

class MyComplex extends String { ... }

MyComplex a = new MyComplex("5+3i");
MyComplex b = new MyComplex("7+4i");
MyComplex c = new MyComplex(a + b);   // would work since a and b are strings,
                                      // and a string + a string is a string.
Hawkweed answered 22/4, 2010 at 12:51 Comment(0)
R
2

With a lot of good points already mentined I would like to add another one -one of the reason of Why String is immutable in Java is to allow String to cache its hashcode , being immutable String in Java caches its hashcode, and do not calculate every time we call hashcode method of String, which makes it very fast as hashmap key to be used in hashmap in Java.

In short because String is immutable, no one can change its contents once created which guarantees hashCode of String to be same on multiple invocation.

If you see String class has is declared as

/** Cache the hash code for the string */
private int hash; // Default to 0

and hashcode() function is as follows -

public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}

If it is already computer just return the value.

Risner answered 10/1, 2014 at 12:6 Comment(0)
C
1

Well, I have some different thought I am not sure whether I am correct or not but in Java String is the only object which can be treated as a primitive data type as well I mean we can create a String object as String name="java". Now like others primitive datatypes which are copy by value not copy by reference String is expected to have same behavior so thats why String is final. Thats what my thought it. Please ignore if its completely illogical.

Conspectus answered 8/12, 2010 at 20:8 Comment(1)
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.Zone
H
1

The finality of strings also defends them as a standard. In C++ you can create subclasses of string, so every programming shop could have its own version of string. This would lead to a lack of a strong standard.

Halona answered 10/12, 2012 at 18:5 Comment(0)
P
1

Most of the answers are related to the immutability -- why an object of String type cannot be updated in place. There is a lot of good discussion here, and the Java community would do well to adopt immutability as a principal. (Not holding my breath.)

However the OP's question is about why it's final -- why can it not be extended. Some here did take this on, but I would agree with the OP that there is a real gap here. Other language allow devs create new nominal types for a type. For example in Haskell I can create the following new types that are identical at run-time as text, but provide bind-safety at compile time.

newtype AccountCode = AccountCode Text
newtype FundCode = FundCode Text

So I would put the following suggestion forward as an enhancement to the Java language:

newtype AccountCode of String;
newtype FundCode of String;

AccountCode acctCode = "099876";
FundCode fundCode = "099876";

acctCode.equals(fundCode);  // evaluates to false;
acctCode.toString().equals(fundCode.toString());  // evaluates to true;

acctCode=fundCode;  // compile error
getAccount(fundCode);  // compile error

(Or perhaps we could start to ween ourselves off Java)

Proem answered 10/10, 2017 at 23:31 Comment(0)
R
1

Let's say you have an Employee class that has a method greet. When the greet method is called it simply prints Hello everyone!. So that is the expected behavior of greet method

public class Employee {

    void greet() {
        System.out.println("Hello everyone!");
    }
}

Now, let GrumpyEmployee subclass Employee and override greet method as shown below.

public class GrumpyEmployee extends Employee {

    @Override
    void greet() {
        System.out.println("Get lost!");
    }
}

Now in the below code have a look at the sayHello method. It takes Employee instance as a parameter and calls the greet method hoping that it would say Hello everyone! But what we get is Get lost!. This change in behavior is because of Employee grumpyEmployee = new GrumpyEmployee();

public class TestFinal {
    static Employee grumpyEmployee = new GrumpyEmployee();

    public static void main(String[] args) {
        TestFinal testFinal = new TestFinal();
        testFinal.sayHello(grumpyEmployee);
    }

    private void sayHello(Employee employee) {
        employee.greet(); //Here you would expect a warm greeting, but what you get is "Get lost!"
    }
}

This situation can be avoided if the Employee class was made final. Now it's up to your imagination the amount of chaos a cheeky programmer could cause if String Class was not declared as final.

Rusticus answered 6/7, 2018 at 21:33 Comment(0)
L
0

Does JVM know what is immutable? Answer is No, The constant pool contains all immutable fields but all immutable fields/objects are not stored in constant pool only. Only we implement it in a way that it achieves immutablity and its features. CustomString could be implemented without making it final using MarkerInterface which would provide java special behaviour for its pooling, the feature is still awaited!

Loma answered 9/2, 2017 at 13:49 Comment(0)
D
-2

If you create a string once It will consider that,it is a object if you want to modify that, it is not possible,it will create new object.

Domiciliary answered 24/2, 2016 at 14:0 Comment(1)
Please clarify your answer.Steerage

© 2022 - 2024 — McMap. All rights reserved.