实例化接口
扩展初始化界面中提出的问题? ,我们确实实例化一个接口,同时用实现的类初始化它。
我的问题是为什么首先,我们用接口实例化它? 为什么我不能用实现的类直接实例化它? 例如。 :
Doc mydoc = new SimpleDoc();
Doc是接口,SimpleDoc正在实现它。 SimpleDoc有什么问题mydoc = new SimpleDoc(); 哪个会失败?
在系统中依赖抽象类型(接口或抽象类)通常是一种好习惯。
在您的示例中,您确实可以写:
SimpleDoc mydoc = new SimpleDoc()
但问题是使用mydoc
代码将取决于具体类型SimpleDoc
。 这不一定是一个问题,但是,假设你创建了一个Doc
的新实现,比如说ComplexDoc
。
您将声明更改为:
ComplexDoc mydoc = new ComplexDoc();
现在,您传递mydoc
所有场所方法也必须更改。
但是,如果您首先使用Doc
,则只需进行一次更改即可:
Doc mydoc = ComplexDoc();
当您使用Collections API时,这非常有用,其中通常切换另一个的实现或在测试用例中使用Mocking。
如果在客户端代码中使用接口而不是实现类,则可以在不更改客户端代码的情况下更改实现。
如果你写:
SimpleDoc mydoc = new SimpleDoc();
所有进一步的代码可能取决于实现类SimpleDoc
公开的细节。 但如果你写:
Doc mydoc = new SimpleDoc();
进一步的代码我只依赖于Doc
公开的方面,如果你决定将来编写代码,它会使代码工作:
Doc mydoc = new ComplexDoc();
差异的一个很好的例子是List
,它至少有两个实现:
ArrayList LinkedList
如果你写:
List list = new ArrayList();
您可以在以后用以下内容替换它:
List list = new LinkedList();
不破坏依赖于变量list
的代码(假设您没有使用强制转换或reflection来访问list
实现特定function)。
这就是我们所谓的虚拟方法调用或后期绑定
我们来看一个例子。
public interface Vegetarian{} public class Animal{} public class Deer extends Animal implements Vegetarian{}
现在,Deer类被认为是多态的,因为它具有多重inheritance 。 以下示例如下:
A Deer IS-A Animal A Deer IS-A Vegetarian A Deer IS-A Deer A Deer IS-A Object
当我们将引用变量事实应用于Deer对象引用时,以下声明是合法的:
Deer d = new Deer(); Animal a = d; Vegetarian v = d; Object o = d
所有引用变量d,a,v,o
指向堆中的相同Deer
对象。