If they do, when do they use it so I can understand it better and know when to use it.
A final class is simply a class that can't be extended.
(It does not mean that all references to objects of the class would act as if they were declared as final.)
When it's useful to declare a class as final is covered in the answers of this question:
- Good reasons to prohibit inheritance in Java?
If Java is object oriented, and you declare a class
final, doesn't it stop the idea of class having the characteristics of objects?
In some sense yes.
By marking a class as final you disable a powerful and flexible feature of the language for that part of the code. Some classes however, should not (and in certain cases can not) be designed to take subclassing into account in a good way. In these cases it makes sense to mark the class as final, even though it limits OOP. (Remember however that a final class can still extend another non-final class.)
Answer from aioobe on Stack OverflowIf they do, when do they use it so I can understand it better and know when to use it.
A final class is simply a class that can't be extended.
(It does not mean that all references to objects of the class would act as if they were declared as final.)
When it's useful to declare a class as final is covered in the answers of this question:
- Good reasons to prohibit inheritance in Java?
If Java is object oriented, and you declare a class
final, doesn't it stop the idea of class having the characteristics of objects?
In some sense yes.
By marking a class as final you disable a powerful and flexible feature of the language for that part of the code. Some classes however, should not (and in certain cases can not) be designed to take subclassing into account in a good way. In these cases it makes sense to mark the class as final, even though it limits OOP. (Remember however that a final class can still extend another non-final class.)
In Java, items with the final modifier cannot be changed!
This includes final classes, final variables, and final methods:
- A final class cannot be extended by any other class
- A final variable cannot be reassigned another value
- A final method cannot be overridden
Videos
Can a final class in Java have final methods?
Can you create a final variable in a final class in Java?
What is the difference between final class and final method in Java?
Okay so I'm fairly new to Java programming but I've been a programmer for a long time (> 10 years). I'm currently writing an application which involves building some strings. I find myself doing this a lot:
String lineTerminator = System.getProperty("line.separator");
StringBuilder sb = new StringBuilder();
...
sb.append("blah blah blah").append(lineTerminator);So I thought I'll just extend the Stringbuilder class and add a method:
public void appendLine(String s);
with the obvious semantics. But I find I can't do that because the StringBuilder class is declared as 'final' why?
I've vaguely googled a bit for this but the answer generally seems to be: "You would make a class Final in Java if you do not want anybody to inherit the features of your class. " and "You don't want anybody to inherit from your class because that code would not work" but I can't seem to get a reasonable explanation for why it might not work. I understand why one might declare a method as 'final' but not a class.
final expresses intent. It tells the user of a class, method or variable "This element is not supposed to change, and if you want to change it, you haven't understood the existing design."
This is important because program architecture would be really, really hard if you had to anticipate that every class and every method you ever write might be changed to do something completely different by a subclass. It is much better to decide up-front which elements are supposed to be changeable and which aren't, and to enforce the unchangeablility via final.
You could also do this via comments and architecture documents, but it is always better to let the compiler enforce things that it can than to hope that future users will read and obey the documentation.
It avoids the Fragile Base Class Problem. Every class comes with a set of implicit or explicit guarantees and invariants. The Liskov Substitution Principle mandates that all subtypes of that class must also provide all these guarantees. However, it is really easy to violate this if we don't use final. For example, let's have a password checker:
public class PasswordChecker {
public boolean passwordIsOk(String password) {
return password == "s3cret";
}
}
If we allow that class to be overridden, one implementation could lock out everyone, another might give everyone access:
public class OpenDoor extends PasswordChecker {
public boolean passwordIsOk(String password) {
return true;
}
}
This is usually not OK, since the subclasses now have behaviour that is very incompatible to the original. If we really intend the class to be extended with other behaviour, a Chain of Responsibility would be better:
PasswordChecker passwordChecker =
new DefaultPasswordChecker(null);
// or:
PasswordChecker passwordChecker =
new OpenDoor(null);
// or:
PasswordChecker passwordChecker =
new DefaultPasswordChecker(
new OpenDoor(null)
);
public interface PasswordChecker {
boolean passwordIsOk(String password);
}
public final class DefaultPasswordChecker implements PasswordChecker {
private PasswordChecker next;
public DefaultPasswordChecker(PasswordChecker next) {
this.next = next;
}
@Override
public boolean passwordIsOk(String password) {
if ("s3cret".equals(password)) return true;
if (next != null) return next.passwordIsOk(password);
return false;
}
}
public final class OpenDoor implements PasswordChecker {
private PasswordChecker next;
public OpenDoor(PasswordChecker next) {
this.next = next;
}
@Override
public boolean passwordIsOk(String password) {
return true;
}
}
The problem becomes more apparent when more a complicated class calls its own methods, and those methods can be overridden. I sometimes encounter this when pretty-printing a data structure or writing HTML. Each method is responsible for some widget.
public class Page {
...;
@Override
public String toString() {
PrintWriter out = ...;
out.print("<!DOCTYPE html>");
out.print("<html>");
out.print("<head>");
out.print("</head>");
out.print("<body>");
writeHeader(out);
writeMainContent(out);
writeMainFooter(out);
out.print("</body>");
out.print("</html>");
...
}
void writeMainContent(PrintWriter out) {
out.print("<div class='article'>");
out.print(htmlEscapedContent);
out.print("</div>");
}
...
}
I now create a subclass that adds a bit more styling:
class SpiffyPage extends Page {
...;
@Override
void writeMainContent(PrintWriter out) {
out.print("<div class='row'>");
out.print("<div class='col-md-8'>");
super.writeMainContent(out);
out.print("</div>");
out.print("<div class='col-md-4'>");
out.print("<h4>About the Author</h4>");
out.print(htmlEscapedAuthorInfo);
out.print("</div>");
out.print("</div>");
}
}
Now ignoring for a moment that this is not a very good way to generate HTML pages, what happens if I want to change the layout yet again? I'd have to create a SpiffyPage subclass that somehow wraps that content. What we can see here is an accidental application of the template method pattern. Template methods are well-defined extension points in a base class that are intended to be overridden.
And what happens if the base class changes? If the HTML contents change too much, this could break the layout provided by the subclasses. It is therefore not really safe to change the base class afterwards. This is not apparent if all your classes are in the same project, but very noticeable if the base class is part of some published software that other people build upon.
If this extension strategy was intended, we could have allowed the user to swap out the way how each part is generated. Either, there could be a Strategy for each block that can be provided externally. Or, we could nest Decorators. This would be equivalent to the above code, but far more explicit and far more flexible:
Page page = ...;
page.decorateLayout(current -> new SpiffyPageDecorator(current));
print(page.toString());
public interface PageLayout {
void writePage(PrintWriter out, PageLayout top);
void writeMainContent(PrintWriter out, PageLayout top);
...
}
public final class Page {
private PageLayout layout = new DefaultPageLayout();
public void decorateLayout(Function<PageLayout, PageLayout> wrapper) {
layout = wrapper.apply(layout);
}
...
@Override public String toString() {
PrintWriter out = ...;
layout.writePage(out, layout);
...
}
}
public final class DefaultPageLayout implements PageLayout {
@Override public void writeLayout(PrintWriter out, PageLayout top) {
out.print("<!DOCTYPE html>");
out.print("<html>");
out.print("<head>");
out.print("</head>");
out.print("<body>");
top.writeHeader(out, top);
top.writeMainContent(out, top);
top.writeMainFooter(out, top);
out.print("</body>");
out.print("</html>");
}
@Override public void writeMainContent(PrintWriter out, PageLayout top) {
... /* as above*/
}
}
public final class SpiffyPageDecorator implements PageLayout {
private PageLayout inner;
public SpiffyPageDecorator(PageLayout inner) {
this.inner = inner;
}
@Override
void writePage(PrintWriter out, PageLayout top) {
inner.writePage(out, top);
}
@Override
void writeMainContent(PrintWriter out, PageLayout top) {
...
inner.writeMainContent(out, top);
...
}
}
(The additional top parameter is necessary to make sure that the calls to writeMainContent go through the top of the decorator chain. This emulates a feature of subclassing called open recursion.)
If we have multiple decorators, we can now mix them more freely.
Far more often than the desire to slightly adapt existing functionality is the desire to reuse some part of an existing class. I have seen a case where someone wanted a class where you could add items and iterate over all of them. The correct solution would have been to:
final class Thingies implements Iterable<Thing> {
private ArrayList<Thing> thingList = new ArrayList<>();
@Override public Iterator<Thing> iterator() {
return thingList.iterator();
}
public void add(Thing thing) {
thingList.add(thing);
}
... // custom methods
}
Instead, they created a subclass:
class Thingies extends ArrayList<Thing> {
... // custom methods
}
This suddenly means that the whole interface of ArrayList has become part of our interface. Users can remove() things, or get() things at specific indices. This was intended that way? OK. But often, we don't carefully think through all consequences.
It is therefore advisable to
- never
extenda class without careful thought. - always mark your classes as
finalexcept if you intend for any method to be overridden. - create interfaces where you want to swap out an implementation, e.g. for unit testing.
There are many examples where this “rule” has to be broken, but it usually guides you to a good, flexible design, and avoids bugs due to unintended changes in base classes (or unintended uses of the subclass as an instance of the base class).
Some languages have stricter enforcement mechanisms:
- All methods are final by default and have to be marked explicitly as
virtual - They provide private inheritance that doesn't inherit the interface but only the implementation.
- They require base class methods to be marked as virtual, and require all overrides to be marked as well. This avoids problems where a subclass defined a new method, but a method with the same signature was later added to the base class but not intended as virtual.