为什么要声明一个接口然后在Java中用它实例化一个对象?

bot*_*bot 22 java oop polymorphism interface

我和朋友正在学习Java.我们今天正在研究接口,我们讨论了如何使用接口.

我朋友给我看的示例代码包含:

IVehicle modeOfTransport1 = new Car();
IVehicle modeOfTransport2 = new Bike();
Run Code Online (Sandbox Code Playgroud)

其中IVehicle的是,在这两款车和自行车类实现的接口.定义接受IVehicle作为参数的方法时,可以使用接口方法,当运行代码时,上述对象正常工作.然而,当您按照通常的意愿声明汽车和自行车时,这非常适用:

Car modeOfTransport1 = new Car();
Bike modeOfTransport2 = new Bike();
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是 - 为什么在声明和实例化modeOfTransport对象时,你会使用前一种方法而不是后者?有关系吗?

Osc*_*mez 13

使用接口声明它们是一个很大的好处,这就是所谓的"编码到接口"而不是"编码到实现",这是一个很大的面向对象设计(OOD)原则,这样你就可以声明一个方法像这样:

public void (IVehicle myVehicle)
Run Code Online (Sandbox Code Playgroud)

这将接受任何实现该接口的对象,然后在运行时它将调用这样的实现:

public void (IVehicle myVehicle)
{
    myVehicle.run() //This calls the implementation for that particular vehicle.
}
Run Code Online (Sandbox Code Playgroud)

要回答原始问题,为什么要使用其中一个,有几个原因:

1)使用接口声明它们意味着您可以稍后将该值替换为实现该接口的任何其他具体类,而不是被锁定到该特定的具体类中

2)您可以通过使用接口声明它们来充分利用多态性,因为每个实现都可以在运行时调用正确的方法.

3)您遵循代码的OOD原则到接口

  • @Mat是的我知道这一点,我在解释通过使用接口声明它们,你编程的接口而不是实现,这可能像上面的例子一样有用. (4认同)
  • 抱歉,但这根本不能回答问题。发帖者问的是为什么要执行“IInterface var = new ConcreteClass();”,而不是接口如何工作。 (2认同)

Lar*_*abe 9

那没关系.

真正重要的是在需要在IVehicle上运行的其他接口.如果他们接受参数并将值返回为IVehicle,那么代码将更容易扩展.

如您所述,可以将这些对象中的任何一个传递给接受IVehicle作为参数的方法.

如果您有后续代码使用了Car或Bike特定的操作,那么将它们声明为Car或Bike将是有利的.Car and Bike特定操作可用于每个相关对象,并且两者都可以作为IVehicle使用(即可以传递).


jto*_*ron 6

你真的在问:我应该使用什么样的参考类型?

通常,您希望尽可能使用一般的引用类型,以便仍然可以访问所需的行为.这意味着您的具体类型的任何接口或父类,而不是具体类型本身.当然,不要把这一点放得太远 - 例如,你当然不想宣布一切都是一个Object!

考虑以下选项:

Set<String> values1 = new TreeSet<String>();
TreeSet<String> values2 = new TreeSet<String>();
SortedSet<String> values3 = new TreeSet<String>();
Run Code Online (Sandbox Code Playgroud)

这三个都是有效的,但通常第一个选项values1更好,因为你只能访问Set接口的行为,所以以后你可以很容易地交换另一个实现:

Set<String> values1 = new HashSet<String>();
Run Code Online (Sandbox Code Playgroud)

小心使用第二个选项values2.它允许您以TreeSet这样的方式使用实现的特定行为,即在不同的实现中交换Set变得更加困难.只要这是你的目标,这很好.因此,在您的示例中,仅当您需要访问不在界面中的内容时才使用CarBike引用IVehicle.请注意,以下情况不起作用:

TreeSet<String> values2 = new HashSet<String>(); // does not compile!
Run Code Online (Sandbox Code Playgroud)

有时您仍需要访问不是最常规类型的方法.这在第三个选项中说明values3- 引用更具体Set,它允许您依赖SortedSet以后的行为.

TreeSet<String> values3 = new ConcurrentSkipListSet<String>();
Run Code Online (Sandbox Code Playgroud)

有关引用类型的问题不仅适用于声明变量的位置,还适用于必须指定每个参数类型的方法.幸运的是,"尽可能使用一般参考类型"经验法则也适用于方法参数.


Vin*_*nie 5

对接口而不是实现进行编程。

当您对接口进行编程时,您将编写可以处理任何类型车辆的代码。因此,将来您的代码无需修改,就应该可以与火车和飞机一起使用。

如果您忽略该界面,那么您将陷入汽车和自行车的困境,并且任何新车辆都将需要额外的代码修改。

这背后的原理是:

对扩展开放,对修改关闭。