Java中接口的重要性

时间:2013-05-26 16:10:33

标签: java interface

假设我们有两个类TigerAeroplane。 这两种类型的一个共同点是速度。我知道创建超类ClassWithSpeed然后从中派生子类AeroplaneTiger是不合逻辑的。 相反,最好创建一个包含方法speed()的接口,然后在AeroplaneTiger中实现它。我明白了。但是,如果没有接口,我们可以做同样的事情。我们可以在speed()中定义方法Aeroplane,在speed()中定义方法Tiger。 唯一(也许是非常大的)缺陷是我们无法通过接口引用“到达”TigerAeroplane的对象。

我是Java和OOP的初学者,如果有人向我解释接口的作用,我将非常感激。 干杯!

12 个答案:

答案 0 :(得分:70)

这是:

public int howFast(Airplane airplane) {
    return airplane.speed();
}

public int howFast(Tiger tiger) {
    return tiger.speed();
}

public int howFast(Rocket rocket) {
    return rocket.speed();
}

public int howFast(ThingThatHasntBeenInventedYet thingx) {
    // wait... what? HOW IS THIS POSSIBLE?!
    return thingx.speed();
}

...

VS

public int howFast(Mover mover) {
    return mover.speed();
}

现在,想象一下将来必须返回并更改所有howFast功能。

接口或否,每个类都必须实现或继承speed()方法。界面允许您更轻松地使用这些不同的类,因为它们每个都承诺以某种方式运行。您将调用speed(),他们将返回int,因此您不必为每个可能的类编写单独的方法。

当您发现由于相对论物理学的突破而需要以不同的方式处理速度时,您只需要更新调用speed()的方法。当你的曾孙女为HyperIntelligentMonkeyFish写一个班级时,她不必拆解你的古代二进制文件并进行修改,以便你的代码可以监视和控制她的突变军队。她只需要声明HyperIntelligentMonkeyFish implements Mover

答案 1 :(得分:8)

接口允许Java,因为它是静态类型的,可以解决多种继承限制,达到语言设计者认为值得的程度。

在动态语言(如Python,Ruby等)中,您可以在任意对象上调用speed方法,并在运行时发现它是否存在。

另一方面,Java是静态类型的,这意味着编译器必须同意该方法将提前存在。在不共享共同祖先的类上执行此操作的唯一方法是,可能只有Object,这是一个接口。

由于对象可以实现任意数量的接口,这意味着您可以获得多重继承的优点(可以为不同方法构建多个不同对象的单个对象),而没有缺点(两个超类中的冲突实现)

使用Java 8,该语言的设计者得出结论,没有任何实现的接口过于严格(他们不喜欢my solution我猜;-)),因此它们允许默认实现,从而扩展了接口的多继承选项,同时仍试图通过a complex set of precedence rules避免冲突的实现问题,以便有一个明确的默认实现来执行。

答案 2 :(得分:6)

我试图通过以下示例解释界面的优势 -

假设您有另一个类,您需要使用老虎或飞机作为参数。因此,通过使用界面,您可以使用

进行调用
someObject.someMethod(ClassWithSpeed)

但如果你不使用界面,你可以使用

someObject.someMethod(Tiger)
someObject.someMethod(AeroPlane)

现在你该怎么办?你可能的答案就像,"I will use two overloaded method".

到目前为止这没关系,但是

假设您需要添加更多选项(例如汽车,骑行,兔子,乌龟等...... 100个其他选项)。那么你将如何改变你现有的代码呢?你需要改变很多东西......

上面的整个例子只有一个目的。也就是说

  

“我们需要界面来创建更好,可重用且适当的面向对象   设计“

N.B。

  1. 如果您确定程序太小而且您永远不需要更改它们,那么我认为没有接口就可以实现

答案 3 :(得分:5)

定义接口允许您定义不仅适用于Airplane和Tiger的方法,还可以定义共享相同接口的其他类。

例如,假设您的界面是IObjectWithSpeed。然后你可以定义一个这样的方法 - 在一个操作IObjectWithSpeed对象的类中。

  public double calculateSecondsToTravel( IObjectWithSpeed obj, double distance ) {
       return distance / obj.getSpeed();
  }

接口允许我们满足open/closed principle - 打开扩展,但关闭以进行修改。上面的方法的单个实现不需要修改,因为定义了实现IObjectWithSpeed的新类。

答案 4 :(得分:3)

除了描述这些类的功能之外,可以使用接口的方法,而不需要了解实现它的类,即使对于尚未定义的类也是如此。

例如,如果你需要一个计算有效路由的类Transport,可以给它一个实现ClassWithSpeed作为参数的类并使用它的方法speed()用于计算它需要的东西。通过这种方式,您可以将它与我们的类Aeroplane一起使用,也可以与我们稍后定义的任何类一起使用,比如说Boat。 Java会注意,如果你想使用一个类作为Transport的参数,它将实现ClassWithSpeed,并且任何实现ClassWithSpeed的类都会实现方法speed(),以便它可以使用。

答案 5 :(得分:3)

我想了解很多理论细节,但会尝试用这个例子来解释。

考虑 JDBC API 。它是用于处理Java中与数据库相关的选项的API。现在,业界有这么多的数据库。如何为此编写驱动程序?好吧,快速而肮脏的方法可能是使用我们自己的类和API编写自己的实现。

但从程序员的角度思考。他们会在使用不同的数据库时开始学习 DATABASE DRIVER 的API吗?答案是否定的。

那么问题的解决方案是什么?只需拥有一个定义良好的API,任何人都可以为自己的实现进行扩展。

在JDBC API中,有一些接口是Connection,ResultSet,PreparedStatement,Statement等。现在每个数据库供应商都将实现该接口并为此编写自己的实现。结果? :减少开发人员的工作量,易于理解。

现在,这个自定义实现可能包含哪些内容?这很简单。他们做了什么,以ResultSet接口为例并实现它,并以ResultSet获取的任何方法返回,返回类的实现这样的ResultSet接口

ResultSet rs = new ResultSetImpl(); //这就是他们在内部所做的事情。

所以界面就像合同。它们定义了您的课程能够做什么,并为您的应用程序提供灵活性。您可以使用正确的接口创建自己的API。

希望这会对你有所帮助。

答案 6 :(得分:3)

接口不仅仅是方法签名。

这是一种代表合同的类型。合同是事物,而不是方法签名。当一个类实现一个接口时,这是因为有一个共享行为的契约,该类有兴趣作为一个类型实现。该合同是通过指定的成员实现的,这些成员通常是方法主体,但也可能包含静态最终字段。

老虎和飞机都可能被表达为具有通过speed()实现的共同行为的类型......如果是这样,那么界面代表表达该行为的合同。

答案 7 :(得分:1)

编译器使用接口(作为语言构造)来证明方法调用是有效的,并允许您使依赖类与实现类交互,同时尽可能少地了解实现类。

答案 8 :(得分:1)

这是一个非常广泛的问题,可以给出一个简单的答案。我可以推荐一本书Interface Oriented Design: With Patterns。它解释了接口的所有功能。为什么我们不应该避免它们。

答案 9 :(得分:1)

在语言层面,如你所提到的,接口的唯一用途是能够以通用方式引用不同的类。然而,在人员层面上,情况看起来不同:IMO Java在大型项目中使用时非常强大,其中设计和实施由不同的人完成,通常来自不同的公司。现在,系统架构师可以创建一堆类,然后实现者可以直接在他们的IDE中插入并开始处理它们,而不是在Word文档上编写规范。 换句话说,它更方便,而不是声明“类X实现方法Y和Z以使其用于目的A,只是说”类X实现接口A“

答案 10 :(得分:1)

你是否尝试过使用组合?如果我想要2个不同的类来继承相同的能力,我会使用一个类,它通过使用抽象类和检查实例来获取它所使用的类型的对象。接口可用于强制方法包含在类中,但不需要任何实现,也不适用于2组编码器在不同的编码区域工作。

Class Tiger {
  public MovingEntity mover;

 public Tiger(){

  mover.speed=30;
  mover.directionX=-1;
  mover.move(mover);

 }

}
Class Plane {
  public MovingEntity mover;

 public Plane(){
  mover.speed=500;
  mover.directionX=-1;
  mover.move(mover);

 }


Abstract Class Moverable(){
  private int xPos;
  private int yPos;
  private int directionX;
  private int directionY;
  private int speed;


Class MovingEntity extends Moverable {
 public void move(Moverable m){
   if(m instanceof Tiger){

      xPos+=directionX*speed;
      yPos+=directionY*speed;

   }else if(m instanceof Plane){
      xPos+=directionX*speed;
      yPos+=directionY*speed;

   }
 }

答案 11 :(得分:0)

因为创建界面会为所有这些类提供Polymorphism,即Tiger和Airplane。

当基类的功能将成为子类功能的核心时,您可以从(抽象的或具体的)类扩展。

除了核心功能之外,还希望在类中添加增强功能时使用接口。所以使用接口会给你多态性,即使它不是你的类的核心功能(因为你通过实现接口输入了合同)。与为每个类创建speed()方法相比,这是一个巨大的优势。