如果我们可以简单地覆盖超类的方法或使用抽象 类,为什么还要使用接口?

Why should we use interface if we can simply override methods of the superclass or use abstract classes?

我有两个程序,一个使用接口实现,另一个仅使用 classes 实现 - 我读过使用接口的优点是它可以提供它自己的 super class 方法的实现,但这可以使用抽象 classes 或方法覆盖来完成。接口的作用是什么?
在什么样的层次结构和情况下使用界面最有利?

界面

interface Shape
{
    void area(int x, int y);
}
class Rectangle implements Shape
{
    @Override
    public void area(int length, int breadth)
    {
        System.out.println(length*breadth);
    }
}
class Triangle implements Shape
{
    @Override
    public void area(int base, int height)
    {
        System.out.println(base*height);
    }
}
public class ShapeUsingInterface
{
    public static void main(String X[])
    {
        Rectangle r = new Rectangle();
        Triangle t  = new Triangle();

        r.area(5, 4);
        t.area(6, 3);
    }
}


CLASS

class Shape
{
    void Area(int x, int y)
    {
        System.out.println(x*y);
    }
}
class Rectangle extends Shape
{

}
class Triangle extends Shape
{
    @Override
    void Area(int base, int height)
    {
        System.out.println((0.5)*base*height);
    }
}
public class CalculateArea 
{
    public static void main(String X[])
    {
        Rectangle r = new Rectangle();
        Triangle t = new Triangle();

        r.Area(4, 5);
        t.Area(6, 8);
    }
}

接口定义契约。比如说:

interface MusicPlayer
{
  public void shuffle();
}

现在每个 class 实现 接口都可以有自己的算法来实现 shuffle 方法,这取决于他们。抽象class类似于接口,抽象class定义几个方法普通,其他方法留给以我们自己的方式实施。喜欢

abstract class MusicPlayer
{
  public void turnOff()
  {
     //kill the app
  }

  abstract public void shuffle();
}

使用接口,您可以实现多个接口,但只能扩展一个 class。

要解释为什么要使用接口,首先要明白一个继承的问题。它被称为 Diamond Problem。简单来说,如果一个class,D继承自两个class,BC,而BC都继承来自同一个 class AD 得到了 A 中方法的哪个实现?

我们剩下的是方法歧义 Java 不喜欢!所以防止这种情况的方法是确保 D 只能 有一个 一个超级 class,这样它就可以继承自 ABC,但绝不会超过一个。这样就避免了这个问题,但是我们失去了多重继承提供的所有好处!

进入界面。这使我们能够享受多重继承的好处(将单个 class 引用为各种不同的类型)并且仍然避免菱形问题,因为实现 class 提供了方法。这消除了方法的歧义。

这意味着,例如:

public abstract class MyClass {
    public void doSomething();
}

public class MyConcreteClass extends MyClass {
    public void doSomething() {
        // do something
    }
}

您可以将 MyConcreteClass 的实例引用为

 MyClass class = new MyConcreteClass();

 MyConcreteClass class = new MyConcreteClass();

但鉴于此实现,没有别的。你不能 extend 更多 classes 因为你可能会遇到钻石问题,但你可以包含一个 Interface

public class MyConcreteClass extends MyClass implements Serializable {
}

突然间,你可以说..

Seralizable myClass = new MyConcreteClass();

因为myClass是一个Serializable。当一个方法可能不需要 知道 它是 MyConcreteClass 的一个实例时,这对于彼此解耦 class 非常有用,只需要知道它有一个必要的方法子集。

简而言之:你可以实现很多接口,但是你只能继承一个class.

您可以将 interfaces 视为一种社会契约,它规定所有实现接口的 classes 都应该定义接口中声明的方法。这在实现它们的所有 classes 之间创建了连续性,如果您希望所有这些 classes 具有相同的行为,那就太棒了。由于接口本身不声明实现,因此它将其留给实现它的 class 。通过这种方式,您可以创建许多机器,例如,它们都有一个开始按钮,您可能希望它们都拥有。更好的说法是 要求 他们都拥有,社会契约确保情况如此,因为您必须实现接口的每个方法!这是编译器要求的。

A class 覆盖了另一个 class 中的所有方法(通过扩展 class 并在其上实现)并没有真正说明它将永远如此信守承诺。知道 class 会忠诚的好处已经消失,你掩盖了它背后的逻辑。查看是否所有方法都被覆盖会不太清楚,这是不好的做法。为什么不把你的逻辑说清楚,实际用一个接口来实现社会契约。

Abstract classes 有点不同,因为它们也实现方法,正如普通 classes 所见,并且还作为接口工作,因为它们还要求您实现已声明但未实现的方法。 java8个接口也可以做到这一点。

我会说在你的例子中 Shape 绝对不应该是 class,而是接口。您已经为面积计算提供了默认实现 x*y,但是在大多数形状的情况下,此实现不正确。

如果您要添加新形状,您将继承方法但实现不正确。您必须记住检查所有 classes 中的所有方法以验证继承的方法。在界面的情况下你不能犯这个错误。