Version 1, you import a third party library:
public class ThirdParty
{
public void calculateAndPrintResult()
{
System.out.println("1");
}
}
public class Mine extends ThirdParty
{
public void calculateAndPrintResult()
{
super.calculateAndPrintResult();
this.printResult();
}
protected void printResult()
{
System.out.println("2");
}
public static void main(String[] arguments)
{
Mine mine = new Mine();
mine.calculateAndPrintResult();
// Prints 1, 2
}
}
Version 2, third party has refactored and introduced printResult. You swap in the new third party library and suddenly the behavior has changed: public class ThirdParty
{
public void calculateAndPrintResult()
{
this.printResult();
}
protected void printResult()
{
System.out.println("1");
}
}
public class Mine extends ThirdParty
{
public void calculateAndPrintResult()
{
super.calculateAndPrintResult();
this.printResult();
}
protected void printResult()
{
System.out.println("2");
}
public static void main(String[] arguments)
{
Mine mine = new Mine();
mine.calculateAndPrintResult();
// Prints 2 ! (wrong)
}
}
While this example is trivial, bear in mind, when you have programming in the large, i.e. large codebases with a lot of third party libraries and many teams of developers, you would rather not have surprises like this pulled on you, or you pulling surprises like this on other people.It can take a lot of work tracking down this kind of bug.
When you finally realize this type of issue arises despite everyone following "best practice" OOP, then the reason is because "best practice" OOP is not actually best practice.
I can see how that would become a problem, a potentially terrible problem, but for a situation like that, wouldn't private methods solve that problem?
I can see more complex situations with this, but at some point, and they'd be annoying to break down. I don't throw out my position on this, though, as good documentation could help at least a few cases of this. Also, newer versions of Netbeans encourage the use of the @Override attribute, to help ensure things like this down happen, I imagine (I don't actually know what the @Override attribute is for, as I've only used it in large Java projects where I was the only developer).
edit: unless you misspell the method you intend to override and forget to include the annotation, in which case the compiler can't help you :-)
Not if the third party developer intends to override it in his own subclasses.
Documentation may solve the issue, but this goes against the "just works" philosophy.
The root of the problem is versioning. Your class was developed against version 1 of the base class. You expect further changes in implementation of the base class should not materially affect your running code.
To achieve this, one of the sacrifices is the all methods are not overridable by default (i.e. not virtual), but instead have to be explicitly declared virtual AND the subclass has to explicitly state they wish to override the base class.
It is namespace pollution of a very subtle and devious kind.
Implementation inheritance breaks encapsulation. It creates an intimate entanglement between the internal implementation details of the super- and sub-classes. Every time you extend a class or override a method that wasn't explicitly and carefully designed to be subclassed and overridden safely, you are _writing hacky code_.
There are, of course, places for hacky code. If you understand why something is hacky and feel it's a worthwhile trade-off then by all means you should be able to do it. Java, though, encourages people to pepper their code with such hacks before they have learned why they shouldn't.