17

I know that java.lang.String class is declared as final for security and performance related reasons.

What I'm not understanding is the part that whether same purpose could be achieved using all final variables and final methods instead of declaring final class ?

In short, what is the difference between below two code snippets .. e.g

public class final String { .. } 

v/s

// non final class
public class String {

// all final variables
private final char[] value;

// all final methods
public final String subString() { .. }
public final int length() { return value.length;}

// etc
}

EDITS

In simple words, can I achieve the same level of immutability by going with either approach ? Are they both good to make objects immutable ?

Saurabh Gokhale
  • 53,625
  • 36
  • 139
  • 164

9 Answers9

15

Final classes cannot be extended.

Non final classes with final methods, can be extended (new methods can be added in subclasses) but the the existing final methods cannot be overridden.

Adam Siemion
  • 15,569
  • 7
  • 58
  • 92
7

The final-modifier on a class does not mean that the properties are also final and immutable. It just means that the class cannot be a parent-class anymore. It is not possible to extend a final class.

See Use of final class in Java

Community
  • 1
  • 1
treeno
  • 2,510
  • 1
  • 20
  • 36
  • See my edited question. I'm asking about something different. – Saurabh Gokhale Aug 26 '14 at 10:58
  • 1
    @peeppeep I don't know about the specifics of Java's String class, but to round it up generally: there's not a _huge_ difference between 100% final methods and a final class. Declaring a class as final, however, clearly states the intention (i.e. the class should not be extended). – ljacqu Aug 26 '14 at 11:01
  • @peepeep, oh, then I still don't understand you 100%. If you want to achieve immutability then I still don't think that you can do that by setting the class to final. – treeno Aug 26 '14 at 19:33
3

Final has different effects deppending on where you use it.

If a class its final, it can't be subclassed.

If a method its final it can't be overriden by any subclass.

If a variable its final it can only be initialized once, making it constant.

Mognom
  • 214
  • 1
  • 3
3

You forgot about Constructor. Constructor cannot be final.To avoid Is-A situations.

If you are not marking class as final though all of your methods are final, still we can extend String and can cheat threads claiming that my class also a String class.

If String alone is not final and methods are final, the below is legal which is causes mess

public class MyUnTrustedClass extends String {

   void MyUnTrustedClass(String virus){
        super(virus);
     }

}
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • 1
    Why would your hypothetical `MyUnTrustedClass` cause a mess (reminder: we are working under the assumption that all `String` methods are `final`)? – Jean Hominal Aug 26 '14 at 15:12
  • @JeanHominal: I don't think the example is a good one; a better issue might be the constructor that takes a `char[]` and stores the reference directly. – supercat Aug 26 '14 at 15:42
  • @supercat: It is not a better example. The crux here is that there is a big difference between constructor chaining and method overriding - that is, only method overriding happens silently with regard to the caller. Consequently, I affirm that, under the assumption that *all* methods of `String` are `final`, and under the assumption that reflection is not used, that `MyUnTrustedClass` cannot do any damage that `String` would not do. – Jean Hominal Aug 26 '14 at 15:55
  • @JeanHominal: If the constructor which takes `char[]` and stores it directly were `protected` rather than `private`, a `MyUntrustedClass` could create a real mess by passing an array which had been or would be exposed to the outside world. The question of whether the constructor of a `final` class is `protected` or `private` is of course moot, but if the class weren't `final` having that constructor be `protected` would have both substantial usability benefits and security risks. – supercat Aug 26 '14 at 16:05
  • @supercat: I guess that I should have been more explicit, that the only modification to `String` I was considering were: 1 - remove `final` from the class declaration and 2 - add `final` to every method declaration. I thought these were the two designs we were comparing. – Jean Hominal Aug 26 '14 at 16:46
  • @JeanHominal: For a `final` class, constructor access qualifiers for "protected" and "package-private" are synonymous; that a constructor in a `final` class doesn't allow protected` access doesn't mean the author wouldn't allow such access if there might be a derived class which could actually make use of it. – supercat Aug 26 '14 at 16:59
1
public final String { ... }
public ExtendedString extends String { ... } // compiler error

public String { ... }
public ExtendedString extends String { ... } // fine

A little more explanation:

Making a class final also implicitly makes all methods final but also prohibits to even extend the class. Making the methods final only still allows to extend the class and only prohibits to override the final methods. In the latter case you can still declare completely new methods in the extending class.

A non-final String class with all final methods would still be immutable (if all other immutability aspects apply). Note that making a class final is far too less effort for making it immutable. In fact, even a non-final class can be immutable if designed correctly.

Seelenvirtuose
  • 20,273
  • 6
  • 37
  • 66
  • I can understand that. But what is the logical reason or difference between two approaches ? Can we substitute one approach for another to achieve String immutability ? – Saurabh Gokhale Aug 26 '14 at 10:49
  • No, public final String doesn't mean that String would be immutable. – treeno Aug 26 '14 at 10:53
  • @treeno I never said that. In fact, I said the opposite. – Seelenvirtuose Aug 26 '14 at 10:57
  • @Seelenvirtuose I was talking (writing) to peepeep. What I wanted to say was: No, we cannot substitute one approach for another to achieve String immutability. – treeno Aug 26 '14 at 19:25
1

What I'm not understanding is the part that whether same purpose could be achieved using all final variables and final methods instead of declaring final class ?

The purpose of declaring a class as final is not the same as the purpose behind declaring all methods in a class as final.

Final Classes

When I declare a class A as final, I'm indicating that such a class is frozen, it is not intended for extension, and that it is not to be used in any other way other than expressed in its structure and declarations. Class A by virtue of being final is not open to refinement.

NOTE 1: Wherever you need to use something with that is of type A, there is one, and only one class, one type, namely A that you can use. The restriction is intentional as per whatever design you pursue or as per your requirements.

The java.lang.System class is a prime example. At run-time there is one type of system. One could have multiple instances of that system, (or, as in Java, a kind of singleton wrapper to a system.) But the type, the capabilities of that System type is one and only one.

Classes with Final Methods

On the other hand, a class A with all methods final is simply saying whatever I provide to you, you cannot extend. You can add more functionality or state to an extension of me, though.

NOTE 2: Wherever you need to use a class A that is not final, but has most if not all methods as final, you can use either an instance of A or a subclass of it. You can use a subclass of A in a different context, but the core functionality provided by type A is not changed.

I cannot imagine a good example where all methods are final. What I typically see is a combination of methods that are final in conjunction to methods that are abstract. In such cases, final methods implement algorithms the details of which are extended via abstract methods.

Consider the unimaginative and rather verbose (on purpose) example of an access monitor class that freezes the main authorization logic (.ie. throw exception for anyone unless that user is authorized.) Further details are left "blank", to be filled by class specializations.

class AccessMonitor {
    abstract AuthorizationMechanism getUnderlyingMechanism();

    final void checkAccess(User user)
    {
         AuthorizationMechanism mechanism = getUnderlyingMechanism()
         if( mechanism.noAccess(user) )
         {
             throw someSecurityException("blah");
         }
         // otherwise, happy camper
    } 
}

class LdapBasedMonitor extends AccessMonitor {
    final AuthorizationMechanism getUnderlyingMechanism()
    {
       return someLdapThingieMajingie;
    } 
}

class DbBasedAuthenticator extends Authenticator {
    final AuthorizationMechanism getUnderlyingMechanism()
    {
       //query some database and make a decision, something something.
    } 
}

In real life we typically see other alternatives over pure refinement by inheritance - composition and delegation comes to mind. In fact, in the general case, one would prefer composition/delegation over inheritance.

However, that is a different subject altogether (one worth a book or two), and an inheritance-based example serves better in this context to illustrate the point of having non-final classes with final methods.

This last example illustrates the idea behind having a non-final class with all methods being final (even if the example leaves room to abstract methods.) When compared with the previous one in this same response, I hope you can see the difference in intention behind the two.

luis.espinal
  • 10,331
  • 6
  • 39
  • 55
  • 1
    "In such cases, final methods implement algorithms the details of which are extended via final methods." Don't you mean "abstract methods"? – Soana Aug 26 '14 at 14:20
  • Oh yes, correct. I'll fix my post accordingly. Thanks for noticing! – luis.espinal Aug 26 '14 at 15:13
0

In simple words, can I achieve the same level of immutability by going with either approach ? Are they both good to make objects immutable ?

No. If the String class is not final, then someone can extend String and create a subclass that is mutable. All Java developers would lose the ability to assume Strings are thread-safe.

Dave C
  • 928
  • 6
  • 12
0

That depends on how we define immutable. We could call an object immutable if

  1. all fields of the object are final, and those of reference type known to point to immutable classes
  2. the observable state of the object must not change, where observable is defined by
    1. accessible through public methods, or
    2. accessible through public methods of some particular class

If we use definition 1, the class itself must be final, as otherwise a subclass could declare a new non-final field.

If we use definition 2.1, the class itself must also be final, as otherwise it could declare a non-final field with getter and setter.

If we use definition 2.2, it is sufficient if every field is final or private, every method final or private, and all existing methods of the class preserve immutability. (We might relax this to include package-protected fields and methods, if we know the package to be sealed, and have verified that all other code in the package preserves immutability and encapsulation).

For the security of the Java platform, definition 2.2, and the implementation approach outlined above, would be sufficient. It would however be quite a bit more complicated to communicate, implement, and verify, than declaring the class itself final. Since a violation of that invariant would compromise the security of the platform, taking the simpler and more reliable approach seems sensible.

meriton
  • 68,356
  • 14
  • 108
  • 175
-1

Final is just like const in C++ thus you can't change the state of it. Immutable is internal functionality of String class. What you can do is use StringBuilder to achieve it. Immutable objects create a new instance in RAM when ever you assign a new value to it. I never changes it state and thus a new instance is created which is refereed to as pass by reference

  • As far as I understand it, this is not true (the first sentence) or only applies to primitive variables (I don't know as I am not that familiar with either the internal workings of C/C++ or Java) and doesn't answer the question (Can one achive the same effect with making the class final vs. making all methods final?) – Soana Aug 26 '14 at 14:26