Why avoid the final keyword? - java

In java, is there ever a case for allowing a non-abstract class to be extended?
It always seems to indicate bad code when there are class hierarchies. Do you agree, and why/ why not?

There are certainly times when it makes sense to have non-final concrete classes. However, I agree with Kent - I believe that classes should be final (sealed in C#) by default, and that Java methods should be final by default (as they are in C#).
As Kent says, inheritance requires careful design and documentation - it's very easy to think you can just override a single method, but not know the situations in which that method may be called from the base class as part of the rest of the implementation.
See "How do you design a class for inheritance" for more discussion on this.

I agree with Jon and Kent but, like Scott Myers (in Effective C++), I go much further. I believe that every class should be either abstract, or final. That is, only leaf classes in any hierarchy are really apt for direct instantiation. All other classes (i.e. inner nodes in the inheritance) are “unfinished” and should consequently be abstract.
It simply makes no sense for usual classes to be further extended. If an aspect of the class is worth extending and/or modifying, the cleaner way would be to take that one class and separate it into one abstract base class and one concrete interchangeable implementation.

there a good reasons to keep your code non-final. many frameworks such as hibernate, spring, guice depend sometimes on non-final classes that they extends dynamically at runtime.
for example, hibernate uses proxies for lazy association fetching.
especially when it comes to AOP, you will want your classes non-final, so that the interceptors can attach to it.
see also the question at SO

This question is equally applicable to other platforms such as C# .NET. There are those (myself included) that believe types should be final/sealed by default and need to be explicitly unsealed to allow inheritance.
Extension via inheritance is something that needs careful design and is not as simple as just leaving a type unsealed. Therefore, I think it should be an explicit decision to allow inheritance.

Your best reference here is Item 15 of Joshua Bloch's excellent book "Effective Java", called "Design and document for inheritance or else prohibit it". However the key to whether extension of a class should be allowed is not "is it abstract" but "was it designed with inheritance in mind". There is sometimes a correlation between the two, but it's the second that is important. To take a simple example most of the AWT classes are designed to be extended, even those that are not abstract.
The summary of Bloch's chapter is that interaction of inherited classes with their parents can be surprising and unpredicatable if the ancestor wasn't designed to be inherited from. Classes should therefore come in two kinds a) classes designed to be extended, and with enough documentation to describe how it should be done b) classes marked final. Classes in (a) will often be abstract, but not always. For

I disagree. If hierarchies were bad, there'd be no reason for object oriented languages to exist. If you look at UI widget libraries from Microsoft and Sun, you're certain to find inheritance. Is that all "bad code" by definition? No, of course not.
Inheritance can be abused, but so can any language feature. The trick is to learn how to do things appropriately.

In some cases you want to make sure there's no subclassing, in other cases you want to ensure subclassing (abstract). But there's always a large subset of classes where you as the original author don't care and shouldn't care. It's part of being open/closed. Deciding that something should be closed is also to be done for a reason.

I couldn't disagree more. Class hierarchies make sense for concrete classes when the concrete classes know the possible return types of methods that they have not marked final. For instance, a concrete class may have a subclass hook:
protected SomeType doSomething() {
return null;
}
This doSomething is guarenteed to be either null or a SomeType instance. Say that you have the ability to process the SomeType instance but don't have a use case for using the SomeType instance in the current class, but know that this functionality would be really good to have in subclasses and most everything is concrete. It makes no sense to make the current class an abstract class if it can be used directly with the default of doing nothing with its null value. If you made it an abstract class, then you would have its children in this type of hierarchy:
Abstract base class
Default class (the class that could have been non-abstract, only implements the protected method and nothing else)
Other subclasses.
You thus have an abstract base class that can't be used directly, when the default class may be the most common case. In the other hierarchy, there is one less class, so that the functionality can be used without making an essentially useless default class because abstraction just had to be forced onto the class.
Default class
Other subclasses.
Now, sure, hierarchies can be used and abused, and if things are not documented clearly or classes not well designed, subclasses can run into problems. But these same problems exist with abstract classes as well, you don't get rid of the problem just because you add "abstract" to your class. For instance, if the contract of the "doSomething()" method above required SomeType to have populated x, y and z fields when they were accessed via getters and setters, your subclass would blow up regardless if you used the concrete class that returned null as your base class or an abstract class.
The general rule of thumb for designing a class hierarchy is pretty much a simple questionaire:
Do I need the behavior of my proposed superclass in my subclass? (Y/N)
This is the first question you need to ask yourself. If you don't need the behavior, there's no argument for subclassing.
Do I need the state of my proposed superclass in my subclass? (Y/N)
This is the second question. If the state fits the model of what you need, this may be a canidate for subclassing.
If the subclass was created from the proposed superclass, would it truly be an IS-A relation, or is it just a shortcut to inherit behavior and state?
This is the final question. If it is just a shortcut and you cannot qualify your proposed subclass "as-a" superclass, then inheritance should be avoided. The state and logic can be copied and pasted into the new class with a different root, or delegation can be used.
Only if a class needs the behavior, state and can be considered that the subclass IS-A(n) instance of the superclass should it be considered to inherit from a superclass. Otherwise, other options exist that would be better suited to the purpose, although it may require a little more work up front, it is cleaner in the long run.

There are a few cases where we dont want to allow to change the behavior. For instance, String class, Math.

I don't like inheritance because there's always a better way to do the same thing but when you're making maintenance changes in a huge system sometimes the best way to fix the code with minimum changes is to extend a class a little. Yes, it's usually leads to a bad code but to a working one and without months of rewriting first. So giving a maintenance man as much flexibility as he can handle is a good way to go.

Related

Inheritance vs Composition: Does composition effectively solve dependency issues? [Effective Java]

I'm semi-familiar with Java and came across something in Effective Java(2017) that didn't make much sense to me.
Below is a piece from the book. (item 18)
Unlike method invocation, inheritance violates encapsulation. In other words, a subclass depends on the implementation details of its superclass for its proper function. The superclass's implementation may change from release to release, and if it does, the subclass may break, even though its code has not been touched. As a consequence, a subclass must evolve in tandem with its superclass, unless the superclass's authors have designed and documented it specifically for the purpose of being extended.
I understand composition may be favored over inheritance in some cases and understood other parts of item 18. However, I find it hard to understand how the composition method prevents the problem mentioned in the paragraph above(dependency on implementation details) - as the author speaks as though composition is better than inheritance because of this. Later in the chapter, Bloch gives an example of a custom Set implementation where he uses a Forwarding Class(which is obviously dependent on the Set interface details). One could argue the Set interface doesn't change as often but in practice changes in the interface may as well cause the Wrapper Class to break(note the book gives an example via Forwarding Class and Wrapper Class).
I guess it makes sense if Bloch meant composition is relatively safer than inheritance because class implementations change more often than interfaces. However, I think there is still a dependency issue between Wrapper Class and Interface, and am confused on why the author didn't mention this more clearly.
Am I mistaken in thinking like this?
(In addition, I'm not sure what encapsulation has to do with this. My understanding of encapsulation is hiding variables using private..)
You should actually provide more on the examples i.e. "Later in the chapter, Bloch gives an example of a custom Set implementation"
Basically the inheritance is that the child class will be affected by the change of parent class. See code below:
public class Baby extends Human{
}
In the code above, if Human implement another public or protected method, Baby will be forced to automatically inherit it. It is quite stringent.
But for composition, a change in the Owner object does not really require a change in the child object, and vice versa up to a certain degree.
public class Human{
private Baby baby;
}
In the code above, Human can have any implementation that may not impact Baby and vice versa. There is more leeway for designing what Baby and Human can do. They can be entirely having lots of different properties and methods.
Ok so I looked up what #LeiYang recommended and came to realize the my question wasn't valid. The given paragraph states "a subclass depends on the implementation details of its superclass for its proper function" - which Object Composition would have no problem with, as it merely makes use of provided methods as is(without overriding). Therefore Object Composition doesn't violate encapsulation and is relatively stable compared to Inheritance.

Differences between abstract and concrete classes in inheritance, constructors, etc

We all know abstract modifier in a class makes it
non-instantiable,
candidate for abstract methods,
Non final, non static, non private
In addition to that I would like to know exactly all the changes or side-effects it represents behind. One cannot ask what he/she does not now yet, but I'd like to know whether is something more to consider in terms of inheriting, constructors etc.
Aside from the two official points described, is there any difference or special behavior between an abstract class and a concrete one to be considered when extending, calling super.
Does the compiler assume it is a regular class and has the properties as such for everything other than disallowing instantiation?
Abstract class is, for the most part, a design concept. It does more for the readers of your code than it does for the compiler. The compiler and JVM support required for them is minimal: it boils down to setting a "do not instantiate me" flag on the class, and checking it when compiling the code and when trying to create an instance through reflection.
Benefits to human readers of your code, on the other hand, are much bigger: they know that you designed your abstract class for inheritance, and see what extension points you made for them through abstract methods. In addition, the compiler will track for them if they have provided overrides for all abstract methods.

Check if object is instanceof a protected class

Say I am using a Java library that has the following method
public static SomeInterface foo();
The interface SomeInterface has multiple implementations, some of which are protected within the library's package. One of these implementation is TheProtectedClass
What would be the best way to check if the object returned by foo() is an instance of TheProtectedClass?
My current plan is to create an Utils class that lives within my project but in the same package as the protected class. This Utils can refer to TheProtectedClass since it is in the same package and thus it can check if an object is instanceof TheProtectedClass.
Any other ideas?
EDIT: Some people are asking "why" so here is more context.
I am using jOOQ and in some part of my code, I want to know if the Field instance that I have is an instance of Lower.
Currently, I use field.getName().equals("lower") but this isn't as robust as I'd like it to be.
I realize that since Lower is a protected class, it isn't part of the API and that it can change but I am ok with that.
Class.forName("TheProtectedClass").isAssignableFrom(foo())
although it is a bad idea for many reasons. You're breaking the encapsulation and the abstraction here. If it's package-private, you shouldn't have to concern with it outside. If it's protected, you should explicitly inherit from it and use the API provided by class for this case.
The less obvious but more correct solution is to get an instance of TheProtectedClass, and compare it by
guaranteedTPCInstance.getClass().isAssignableFrom(foo())
, while still being kind of hacky, at least is more portable and OOPy IMO.
As to your idea of creating a class in the same package as TheProtectedClass to avoid being package-private - it's a viable solution, but a) it breaks the basic principle of encapsulation and the programming contract of the TPC class; packaging is done by library/class authors for a reason - to prevent irresponsible data access and using private API or undocumented proprietary methods, b) it's not always possible (and shouldn't be possible in case of properly designed library classes), since those classes can be not only package-private, but final or effectively final (anonymous inner classes etc) - for the reasons described by Bloch in EJ 2nd, "favor composition over inheritance" item, see also Good reasons to prohibit inheritance in Java? Use of final class in Java etc c) you can't do it with some Java library classes, as you can't define your class to be and use e.g. java.lang package. As such, the only "portable" solution is through reflection and through what I described.
tl;dr The fact you can piggyback another package by mimicking its package definition is an obvious C-style deficiency of Java's syntax (allowing programmer to do what he shouldn't be able to normally do; same goes with some specific reflection methods); hacks made this way are neither maintainable nor safe.
NOTE: If you you expect to do something in a internal implementation-dependent and, at the same time, portable and maintainable (e.g. impervious to implementation changes/class name changes etc) way, you're obviously expecting the impossible.
It appears that the best solution is to create a package in your project that has the same package as the package-private class and either expose TheProtectedClass.class as a Class<?> or simply add a simple method that checks if your Object is instanceof TheProtectedClass.
This does not require reflection, it is fast and relatively safe (compilation will break if the package-private class changes name).

Which languages "have subclassing but no inheritance"?

From the pdf of a java course: http://www.ccs.neu.edu/home/riccardo/courses/csu370-fa07/lect4.pdf
It says:
For those of you that follow at home, let me emphasize that subclassing is not inheritance. We will see inheritance later in the course.
Of course, subclassing and inheritance are related. As we will see inheritance is a code reuse mechanism that lets you reuse code easily when defining subclasses. But subclassing makes sense even when you do not have inheritance.
(Indeed, some languages have subclassing but no inheritance, at least, not inheritance like Java implements.)
Subclassing is a property of classes, and is properly part of the type system of Java. Subclassing is used by Java to determine what methods can possibly be invoked on an object, and to return an error at compile-time when an object does not supply a given method.
I want to know which languages have subclassing but no inheritance, at least, not inheritance like Java implements? (Since I'm not quite understand the concepts, so if I can see it in some actual languages, that would make it clearer)
This is a distinction without a difference. Clearly he is talking about inheritance of methods only when he uses the word "inheritance". He isn't using the term in the canonical way introduced by Wegner87, which is inextricably entwined with subclassing:
Inheritance: A class may inherit operations from “superclasses” and may have its operations inherited by “subclasses”. An object of the class C created by the operation “C new” has C as its “base class” and may use operations defined in its base class as well as operations defined in superclasses.
CS teachers often have strange notions. This has been one of them.

Why is having an abstract subclass of concrete class bad design?

After all ANY java abstract is an abstract subclass of Object. Sometimes we need to force the subclass to implement some methods, but may already have a pretty well defined hierarchy with concrete classes.
For example: I have a well functioning hierarchy with
Vehicle<--- Car
and now I want to add ElectricCar to this hierarchy.
vehicle<--Car<--ElectricCar.
I also want all the different types of electric cars to implement certain behaviors like getBatteryLife or something-
Why would it be a bad idea to make ElectricCar abstract ?
there's nothing wrong in making it abstract. if your business requires you to make it abstract, it's fine. Like you said, lots of classes in Java lib are abstract and still extending Object.
It's not bad, per se. Not common, but not bad. The only thing I can think of is understandability: if I saw a concrete class Car that I could instantiate, I would normally assume that any child of it was also instantiable, because 99% of code works this way.Then I'd be confused, for a second, about not being able to instantiate an ElectricCar.
It could be argued that this pattern breaks the Liskov Substituion Principle since you can't pass "ElectricCar" wherever "Car" is expected if it's declared abstract (you could pass instances of ElectricCar subclasses of course).
In this particular example, the concrete electric cars (hydrogen powered/plug-in/etc?) I would expect to inherit directly from "Car" since they satisfy an "is-a" relationship and are a proper specialisation of "Car". If you wanted to described some common behaviours and traits they should provide then they should also implement an ElectricCar interface.
It seems what you really want is the ability to inherit from Car (since that is what they are) and share/re-use common implementations of electric car related methods. In this case you are looking at a multiple inheritance problem or a need for mixins, neither of which are directly supported in Java.
Providing an abstract class in the middle of a concrete hierarchy may be one way around this, but it's not pretty.
Personally I would prefer to define an Interface for ElectricCar and then allow the implementing class to define the methods. Then you can share the behavior of getBatteryLife through another mechanism.
I've built some pretty deep hierarchies of Inheritance and I tend to avoid them do to the brittle nature they tend to build up over time. One Base class might make sense, but I would think about how you can compose your object model to share behavior w/o inheritance if possible.
In you example I would say that supposedly the Car class should be abstract (or an interface), too. But there is nothing wrong with the ElectricCar being abstract.

Categories

Resources