The final keyword creates a lot of confusion in the Java world. I’ll try to clear things up a bit.
It has different meanings and is often confused with other concepts.
Here’s a quick overview of the three meanings:
- final variable: The (first) assignment is final.
- final class: No other class can extend this one.
- final method: Extending classes can’t…
- …override this nonstatic method.
- …hide this static method.
OK, so far so good. This isn’t so hard to understand. But confusion arises because many think it means other things. I’ll explain why it does not.
1: final variables
A variable is not a value. It has a value. This is a bit different from math class, where x=4 means that x really is 4. And that is true until the professor wipes the board and everything is gone and forgotten. You won’t see a math prof writing x=4 and then x=5 on the next line.
A variable is just a name and you can assign values to it. The final keyword can be added to a variable (local, static or object bound). But the variable isn’t really “final”. The assignment is. The compiler will make sure that there will be one value assigned and then no other. It even tries to make sure that read operations are only made after that assignment (which it can’t always guarantee).
final != immutable
Something can be immutable and in Java the term unmodifiable is used as a synonym. But that describes an object. A variable can’t be immutable. The value is immutable simply because 4 will always be 4 (or call it 1002 if you want). The value of a nonprimitive variable is always a reference to some object (or null). A reference is also just a number and therefore immutable. It won’t change (the address mapped to the reference might change though). You can assign a different, but also immutable, reference to that variable.
You can have a final variable referencing a mutable object. You can have a nonfinal variable referencing an immutable object.
final != constant
A public final static variable isn’t exactly the same as a constant. A constant is something that is given and always the same. But a final field can have a value that changes with each execution of the code. It could depend on some user input or system configuration. That isn’t constant at all. In Java you can have variables with just one final write operation and then it is read only.
More about constants in Java here.
2: final class
final != immutable
So we already know that a variable can’t make an object immutable. The class has to do that. That’s why many think final does that.
Now, I’ll give here the ultimate answer to the question:
How do I make my class immutable?
You simply say it is!
Ok, but how do you say it is immutable?
→ Say it is immutable in the javadoc text you write for your class.
And here’s what you should do:
→ Use @Immutable on that class.
→ Make all fields private
→ Make all fields final (or lazy).
→ Make the class final.
→ Clone all mutable objects in your methods and constructors (defensive copying).
→ Read a text that explains this better than this one.
→ Never forget that reflection still can be used to modify objects.
3: final method
The final keyword can be used on the method level too and is similar to the use on class level.
The strange think in Java is that a method is not final by default, even if it is implemented. But it is best practice to have all methods final or empty or abstract. Not doing so will lead to the “fragile base class problem“.
override != overload
Overloaded methods are methods on their own and not necessarily final. Overloads are always permitted by the compiler. There’s no keyword to prevent this.
PS: I have to say that Microsoft did the right thing when they used better keywords in C#:
- variable: readonly or const
- class: sealed
- method: different design using virtual and override
Scala also uses different keywords.