面向对象的编程语言,例如java,c#,...支持对象类型转换。例如,这在java中完全有效:
URL url = new URL("url");
URLConnection conn = url.openConnection();
if( !conn instanceof HttpURLConnection )
throw new Exception("not http request");
HttpURLConnection con = (HttpURLConnection) conn;
或者我试过的另一个基本例子:
public class Base
{
public void base(){}
}
public class Derived extends Base
{
public void derived(){}
}
Base b = new Derived();
b.base();
派生类具有基类具有的所有方法,以及更多。没有理由不能通过调用派生类构造函数来创建基类。
我还遇到了这个链接http://www.volantec.biz/castingObjects.htm,它解释了对象类型转换如何在内部工作。到目前为止,好的。
但是为什么第一个例子没有使用HttpURLConnection con = new HttpURLConnection("url address")
(我知道HttpURLConnection是一个抽象类)。它看起来更清晰,更简单。另一方面,当你处理interfaces, object typecasting comes in handy时。另一个例子是List<Object>
列表,我有时会在某些类中看到它。这意味着您可以在此列表中保存所有可能的类。之后,如果您知道它是什么类型,您可以将其转换为原始版本。如果只保存要列出的特定类,即List<String>
,List<MyClass>
,则不会更清楚。是否正在使用List<Object>
良好的设计实践?
答案 0 :(得分:8)
在设计类层次结构时,您始终必须牢记Liskov's Substitution Principle (aka, LSP):
派生类型必须完全可替代其基类型。
换句话说,要决定是否应该扩展一个类,你应该问问自己,如果将它改为基类,那么依赖于你的新类的组件是否会得到很好的服务。
强制转换的问题在于,如果您需要将Base类对象转换为Derived类,则意味着您违反了LSP。
如果您需要确保某个对象来自特定的实现,那么您的设计肯定存在问题。
接口就像合同。如果您正在使用不在接口中的实现方法,则意味着您正在破坏该合同,从而在您的代码和实现之间创建耦合。
请记住,您的代码应始终为rely on abstractions rather than concretions。
答案 1 :(得分:0)
通过使用Object类进行转换,基本上为派生类提供了每个可用的权限,即函数永远不会拒绝即将发生的参数,因为你已经提供了对象的访问权限,所以它很危险, 并且根据@Henrique的说法,如果你需要确保一个对象是一个特定的实现,当你期望一个接口时,那么你的设计肯定会出现问题。