DEV Community 👩‍💻👨‍💻

Amar Prakash Pandey
Amar Prakash Pandey

Posted on

Why it is not possible to extend a final class in Java?


Top comments (9)

bertilmuth profile image
Bertil Muth

The final keyword in Java means: „can‘t be modified“. Applied to a field/variable it means: it‘s a constant (the value can’t be modified.) Applied to a class, it means: class can’t be extended (and thus, modified).

elmuerte profile image
Michiel Hendriks

Applied to a field/variable it means: it‘s a constant (the value can’t be modified.)

To be more correct: the variable assignment cannot be modified. Only in case of primitives and immutable objects the value cannot be modified.

final String[] foo = String[] { "bar" };
foo[0] = "quux"; // this is legal.
amarlearning profile image
Amar Prakash Pandey

Thanks, @bertilmuth .

As you said final keyword in java means "can‘t be modified", but still we should be allowed to extend it from another class so that we can use its defined method.

I totally agree that if we try to modify any of its methods then it should give an error, but otherwise we should be allowed to extend that final class and reuse its method in another class.

Please correct me if I am wrong anywhere.

bertilmuth profile image
Bertil Muth

As Kasey Speakman has pointed out, you can extend final classes by composition. Just not inheritance. A class can offer all visible methods of the final class, plus further methods.

kspeakman profile image
Kasey Speakman

The creator of the class explicitly marked it that way because they did not want you to extend it. Probably to avoid having access to its protected members. But I can only guess as to their intentions. Generally, you have to use such a class with composition (create one and put it in a private field in your own class) rather than inheritance.

martinhaeusler profile image
Martin Häusler

First of all, a final class can make sense. Imagine what would happen if somebody were to extend String, Integer or any of the other builtin classes - the JVM would be unable to perform a lot of optimizations. Sometimes, the programmer just didn't want to allow inheritance for architectural reasons. Granted, it's a rare occasion, but the possibility is there if you need it.

That being said, there actually is a possibility to inherit from a final class. This is needed mostly for internal purposes in frameworks like Spring of Hibernate. Using reflection, the final modifier of a class can be disabled at runtime, and the byte code of a class can be generated which extends the formerly final class. Don't try this at home.

cjbrooks12 profile image
Casey Brooks

The final keyword is much more related to the intent behind that class than any physical restriction from Java or the JVM. As others have mentioned, it is technically possible to extend a final class, but it is difficult and dangerous to do so.

In Java, a final class is an opt-in feature, meaning the developer chose to make this class final. They looked at the class and the way it is intended to be used, and decided it makes more sense for it to not be extended. There are several reasons why they might have made this choice:

  • Performance. Especially in low-level platform classes, there are a lot of optimizations that can be done if the specific behavior of a given class is completely known. By forcing these classes to be final, other code can make certain assumptions that improve performance.
    • Example: a field will never be null and so we don't need a null-check. If a class can be extended, we no longer have that guarantee, and to ensure safety we would otherwise have to do a null check every time we wished to use a certain variable.

  • Ensure Correct Framework Usage. When working with a large codebase, you will inevitably be faced with a situation where a given task could be implemented in multiple different ways. By making many of the core framework classes final, the original developer is actually helping guide new developers into the correct/intended way to use the framework.
    • Example (from Android): I am trying to add a Fragment to a particular ViewPager. The Android ViewPager accepts any Fragment instance, but our application logic requires an instance of FragmentProvider (a custom class), not Fragment. This FragmentProvider class is final, and contains methods for loading/unloading fragments and tying them into our custom application lifecycle, which is functionality built on top of the normal ViewPager. Our ViewPager adapter only accepts a list of FragmentProvider as input, so there is only one way to add a new Fragment to do it, and that one way is perfectly in-line with the original developer's intention.

  • Protect Brittle Code. - Another situation which arises in large codebases is the inevitably-brittle class, which is large, filled with spaghetti code, and is quite buggy. By making this class final, we can lock it down and force all consumers to use that class exactly as it is, which makes it a bit easier to wrangle the damage that this class can cause. If it could be extended, not only do we have to make sure that this class itself isn't crashing, but that all classes that extend it aren't also crashing in their own code, and also that the particular combination of overridden methods isn't causing strange, unexpected behavior, both within that class and within the classes that depend on it.

  • Prevent Inheritance-hell. No framework was ever built with the expectation that a class would be extended 10, 20, 30 or more times. It expects it would be extend once, maybe twice. But as the framework grows in size, it is all too easy for extended classes to be extended, and those to be extended, and so on. Having a shallow inheritance tree is better for performance and for understandability, and so a class might make itself final to try and enforce this. It might be at the very first level, so that a class is never extended, or maybe after a couple subclasses have been created, all those will be made final to effectively stop extension-growth beyond that level or in a particular sub-tree. All this helps to keep the code clear and easy to navigate.
    • Anti-example (from Android): The Context base class in Android is a god-class that knows entirely too much, and is fragmented across many different implementations through a deep and confusing hierarchy. An Application is a Context. An Activity is a ContextThemeWrapper which is a ContextWrapper which is a Context. And supporting older versions of android, an AppCompatActivity has 9 extended classes before reaching Context. This makes it confusing to reason about which code is actually being run, and in what order, and it would have probably been a better idea to have made just a few Context-type classes (just Context, Application, and Activity) and have the rest of the needed behavior implemented through composition.
bertilmuth profile image
Bertil Muth

I wrote a post with code examples that will hopefully explain this a bit more concretely.

val_baca profile image
Valentin Baca

Because it's final.

Use composition instead of inheritance if you want to "extend" a final class.

See the Decorator Pattern

Take Your Github Repository To The Next Level

Take Your Github Repository To The Next Level 🚀️: A step-by-step guide on creating the perfect Github repository.