实例化接口

扩展初始化界面中提出的问题? ,我们确实实例化一个接口,同时用实现的类初始化它。

我的问题是为什么首先,我们用接口实例化它? 为什么我不能用实现的类直接实例化它? 例如。 :

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对象。