Java `final` method: what does it promise?
As mentioned, final
is used with a Java method to mark that the method can't be overridden (for object scope) or hidden (for static). This allows the original developer to create functionality that cannot be changed by subclasses, and that is all the guarantee it provides.
This means that if the method relies on other customizable components like non-public fields/methods the functionality of the final method may still be customizable. This is good though as (with polymorphism) it allows for partial customization.
There are a number of reasons to prevent something from being customizable, including:
Performance -- Some compilers can analyse and optimise the operation, especially the one without side-effects.
Obtain encapsulated data -- look at immutable Objects where their attributes are set at the construction time and should never be changed. Or a calculated value derived from those attributes. A good example is the Java
String
class.Reliability and Contract -- Objects are composed of primitives (
int
,char
,double
, etc.) and/or other Objects. Not all operations applicable to those components should be applicable or even logical when they are used in the bigger Object. Methods with thefinal
modifier can be used to ensure that. The Counter class is a good example.
public class Counter {
private int counter = 0;
public final int count() {
return counter++;
}
public final int reset() {
return (counter = 0);
}
}
If the public final int count()
method is not final
, we can do something like this:
Counter c = new Counter() {
public int count() {
super.count();
return super.count();
}
}
c.count(); // now count 2
Or something like this:
Counter c = new Counter() {
public int count() {
int lastCount = 0;
for (int i = super.count(); --i >= 0; ) {
lastCount = super.count();
}
return lastCount;
}
}
c.count(); // Now double count
Why can't a final class be inherited, but a final method can be inherited?
Why can't a final class be inherited, but a final method can be inherited?
Why? Because final
means different things for classes and methods.
Why does it mean different things? Because that is how the Java language designers chose to design the language!
There are three distinct meanings for the final
keyword in Java.
A
final
class cannot be extended.A
final
method cannot be overridden.A
final
variable cannot be assigned to after it has been initialized.
Why did they decide to use final
to mean different things in different contexts? Probably so that they didn't need to reserve 2 or 3 distinct keywords. (In hindsight, that might not have been the best decision. However that is debatable ... and debating it is IMO a waste of time.)
It is worth noting that other keywords have multiple meanings in Java; e.g., static
and default
(in Java 8).
Why an object marked as final can be modified and call non-final method in Java?
Referencing Erik's answer in comments, I found an easy explanation for C++ programmers.
Pet pet;
in Java is like Pet* pet;
in C++.
final Pet pet;
in Java is like Pet * const pet;
in C++ which makes the pointer const
but not the value itself.
Note that there is a subtle difference in Java and C++.
In C++, you have to assign a value when declaring a const
variable but in Java, it lets you do it later but only once.
Why is it considered good practice to mark method parameters as final?
If you mark a method parameter as final
, you can't modify the parameter's value within the scope of the method:
public void xyz(final String parameter) {
parameter = "..." //compiler error!
}
Understand that the value of parameter
is the reference to the object passed to the method, and not the value of the object itself.
By marking the method parameter as final
, the compiler will throw an error upon compilation. This serves as a reminder that you should not modify the value of the parameter within your method.
It's considered a bad practice to modify the original parameter within your method.[1]
If the value of the parameter can change to reference another object, it might not be immediately clear what object is being referenced at any given point within the body of your method.
Consider the following:
public void xyz(String parameter) {
//Complicated logic that might span 20-30 lines.
parameter = "Joe";
//More complicated logic that might span a few lines.
//New logic being added that needs reference to the value of the parameter.
}
In a complicated method, like above, it might be difficult for a programmer to identify what object parameter
references. Furthermore, if the programmer needs a reference to parameter
he no longer has one.
- Is it a good practice to change arguments in Java
Why private method can not be final as well?
Basically, it's allowed because they didn't feel like it's worthwhile to put a special case prohibiting the private
modifier. It's like how you can also declare methods on an interface as public
, or nested classes in an interface as static
, even though those keywords are implied in interfaces. You can also declare final
methods on a final
class, etc.
Java took the stance of not complaining when you add redundant modifiers. They do it consistently.
Local variable needs to be declared final
Since you're not modifying box
in the outer code, using final
is exactly the correct way to solve this problem. It's a promise to yourself (and to the compiler) that the value of box
won't change in the enclosing scope. The compiler will tell you if you break that promise.
There is no compile time or runtime cost to using final
.
Related Topics
How to Find Out What Keystore My Jvm Is Using
Differencebetween an Ordered and a Sorted Collection
Hibernate One-To-One: Getid() Without Fetching Entire Object
Java - How to Receive Point Coordinates After Mouse Button Release (Jfreechart)
Comparing Time Is Incorrect When Picking 12:00
Registering Multiple Keystores in Jvm
Maven: How to Change Path to Target Directory from Command Line
Generate Java Classes from .Xsd Files...
How to Calculate the Difference Between Two Arraylists
Using Javafx in Jre 8, "Access Restriction" Error
Hibernate: Flush() and Commit()
Java Method Invocation VS Using a Variable