This post originated from an RSS feed registered with Java Buzz
by Joe Shelby.
Original Post: an API to bite one in the arse
Feed Title: Joe's Java Jottings
Feed URL: http://www.blog-city.com/bc/
Feed Description: Notes, observations, and occasional other stuff on Java, with concentrations on Swing, XML, and the Semantic (Object) Web.
One of the biggest problems with inheritence for the sake of code reuse is that you can often inherit methods that no longer have any validity in the derived class, yet nothing in the compiler can tell you that unless the derived class goes out of its way to override the method and add a "@deprecated" sign to it. Even then, sections of your code may never get the warning if they refer to the object by its base class anyways (Base b = new Derived()).
Case in point, JDBC.
PreparedStatement logically shares a lot from Statement, from a conceptual level, so it makes sense to have PreparedStatement derive from Statement. However, one method in Statement, if called by a PreparedStatement, utterly breaks every time you use it, assuming you're using PreparedStatement the way it was intended: executeQuery(String query).
If you've gone to the trouble of creating a PreparedStatement using the factory method in Connection, and setting the parameters, you can still accidentally call that version of the method instead of the appropriate executeQuery() with no parameters. This will immediately get the runtime error of "not all variables bound", which at first glance of the code makes no sense, since you can see right there that you've set all the parameters.
All because there's no way for the compiler to tell you that method has no meaning in the derived class. Even in the case of having no parameters to set, the presense of the method in PreparedStatement is useless because it wastes the entire step of "preparing" the query in the first place. it actually evaluates the query *twice*, once at construction, then once again at the execute, since it has no real way of knowing that they are the same thing.
API designers, keep that in mind. If you want to share interfaces through inheritence, but one derived interface might make an inherited method invalid/useless, then refactor -- create a base class with the common methods, and then derived classes with the additional methods that make sense.
Compilers should be able to catch mistakes like this, but they can't when you don't construct your hierarchies correctly.