Object oriented programming languages e.g. java, c#, ... support object typecasting. For example this is perfectly valid in java:
URL url = new URL("url");
URLConnection conn = url.openConnection();
if( !conn instanceof HttpURLConnection )
throw new Exception("not http request");
HttpURLConnection con = (HttpURLConnection) conn;
Or another basic example which I tried:
public class Base
{
public void base(){}
}
public class Derived extends Base
{
public void derived(){}
}
Base b = new Derived();
b.base();
Derived class has all the methods base class has, plus more. There is no reason why you can’t create base class by calling derived class constructor.
I also came across this link http://www.volantec.biz/castingObjects.htm which explains how object typecasting works internally. So far, ok.
But why the first example doesn't use HttpURLConnection con = new HttpURLConnection("url address")
(I know HttpURLConnection is an abstract class). It just seems more clear, more simple. On the other hand when you are dealing with interfaces, object typecasting comes in handy. Another example is List<Object>
list, which I see sometimes in some classes. It means that you can save every possible class in this list. Afterwards you can just cast it to its original, if you know what type it is. Wouldn't it be more clear to save only specific classes to list i.e. List<String>
, List<MyClass>
. Is using List<Object>
good design practise then at all?
When designing a class hierarchy, you always have to keep the Liskov's Substitution Principle (aka, LSP) in mind:
In other words, to decide whether you should extend a class, you should ask yourself if the components that depends on your new class would be well served if you change it to its base class.
The problem with casting is that if you ever need it to convert a Base class object into a Derived class one, it means you are violating the LSP.
If you need to make sure that an object is from an specific implementation when you are expecting an interface, then there surely is something wrong with your design.
Interfaces are like contracts. If you are using a method of the implementation that is not in the interface, it means you are breaking that contract, creating coupling between your code and a implementation.
Remember that your code should always rely on abstractions rather than concretions.