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.