关于Java:如果我们可以简单地重写超类的方法或者使用抽象类,为什么要使用接口呢?

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

本问题已经有最佳答案,请猛点这里访问。

我有两个程序,一个使用接口实现,另一个只使用类实现-我已经读过了,使用接口的好处是它可以提供自己的超类方法实现,但是可以使用抽象类或方法重写来实现。接口的作用是什么?在什么样的层次结构和情况下,使用接口将是最有益的?界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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);
    }
}


要解释为什么要使用接口,必须首先了解继承的问题。这叫做钻石问题。简单地说,如果一个类,D继承了BC两个类,BC都继承了同一个类A的方法,那么D继承了哪个实现方法?

enter image description here

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

进入界面。这允许我们拥有多重继承的好处(将单个类作为各种不同的类型引用),并且仍然可以避免菱形问题,因为实现类提供了方法。这消除了方法的模糊性。

这意味着,例如:

1
2
3
4
5
6
7
8
9
public abstract class MyClass {
    public void doSomething();
}

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

您可以将MyConcreteClass的实例称为

1
 MyClass class = new MyConcreteClass();

1
 MyConcreteClass class = new MyConcreteClass();

但考虑到这个实现,再也没有其他的了。你不能多上14门课,因为你可能会遇到钻石问题,但是你可以包括15门课。

1
2
public class MyConcreteClass extends MyClass implements Serializable {
}

突然间,你可以说……

1
Seralizable myClass = new MyConcreteClass();

因为myClassSerializable。当一个方法可能不需要知道它是MyConcreteClass的一个实例时,只需要知道它有一个必要的方法子集,这对于将类彼此分离是非常好的。

简而言之:可以实现多个接口,但只能继承一个类。


我想说,在您的示例中,Shape肯定不是类,而是接口。您已经为面积计算提供了默认的实现,如x*y,hower,在大多数形状的情况下,这种实现是不正确的。

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


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

覆盖其他类中的所有方法(通过扩展该类并在其上实现)的class并不真正表示它将始终真正遵守这一承诺。知道这个阶级会忠诚的好处已经不复存在了,而你却掩盖了它背后的逻辑。不太清楚是否所有方法都被重写,这是一个糟糕的实践。为什么不把你的逻辑弄清楚,用一个接口实际实现社会契约呢?

抽象类有一点不同,因为它们也实现方法(如普通类所见),而且还作为接口工作,因为它们还要求实现已声明但未实现的方法。在Java 8中,接口也可以做到这一点。


接口定义合同。比如说:

1
2
3
4
interface MusicPlayer
{
  public void shuffle();
}

现在,每个实现接口的类都可以有自己的算法来实现shuffle方法,直到它们为止。抽象类类似于接口,其中一个抽象类定义了一些常用的方法,并让其他方法以我们自己的方式实现。喜欢

1
2
3
4
5
6
7
8
9
abstract class MusicPlayer
{
  public void turnOff()
  {
     //kill the app
  }

  abstract public void shuffle();
}

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