Java中的接口和抽象类与示例混淆
我无法理解何时使用接口而不是抽象类,反之亦然。另外,我对何时使用另一个接口扩展接口感到困惑。很抱歉这篇文章很长,但这非常令人困惑。
创建形状似乎是一个流行的起点。假设我们想要一种对 2D 形状进行建模的方法。我们知道每个形状都会有一个区域。以下两种实现之间的区别是什么:
带接口:
public interface Shape {
public double area();
}
public class Square implements Shape{
private int length = 5;
public Square(){...}
public double area()
return length * length;
}
}
与抽象类:
abstract class Shape {
abstract public double area();
}
public class Square extends Shape {
private length = 5;
public Square(){...}
public double area(){
return length * length;
}
我理解抽象类允许您定义实例变量,并允许您提供方法实现,而接口不能执行这些操作。但在这种情况下,这两种实现似乎是相同的。所以使用任何一个都可以吗?
但现在说我们想要描述不同类型的三角形。我们可以有等腰,锐角和直角三角形。对我来说,在这种情况下使用类继承是有意义的。使用“IS-A”定义:直角三角形“IS-A”三角形。三角形“IS-A”形状。此外,抽象类应该定义所有子类中通用的行为和属性,因此这是完美的:
与抽象类
abstract Triangle extends Shape {
private final int sides = 3;
}
class RightTriangle extends Triangle {
private int base = 4;
private int height = 5;
public RightTriangle(){...}
public double area() {
return .5 * base * height
}
}
我们也可以用接口来做到这一点,三角形和形状就是接口。但是,与类继承(使用“IS-A”关系来定义什么是子类)不同,我不确定如何使用接口。我看到两种方式:
第一种方式:
public interface Triangle {
public final int sides = 3;
}
public class RightTriangle implements Triangle, Shape {
private int base = 4;
private int height = 5;
public RightTriangle(){}
public double area(){
return .5 * height * base;
}
}
第二种方式:
public interface Triangle extends Shape {
public final int sides = 3;
}
public class RightTriangle implements Triangle {
....
public double area(){
return .5 * height * base;
}
}
在我看来,这两种方式都有效。但是,您何时会使用一种方式而不是另一种方式呢?与抽象类相比,使用接口来表示不同的三角形有什么好处吗?即使我们使形状的描述复杂化,使用接口与抽象类似乎仍然是等效的。
接口的一个关键组件是,它可以定义可以在不相关的类之间共享的行为。因此,Flyable接口将出现在Airplane和Bird类中。因此,在这种情况下,很明显接口方法是首选。
此外,为了构建扩展另一个接口的令人困惑的接口:在决定什么是接口时,何时应忽略“IS-A”关系?举个例子:链接。
为什么“VeryBadVampire”应该是一个类,而“Vampire”应该是一个接口?一个“VeryBadVampire”是一个“吸血鬼”,所以我的理解是“吸血鬼”应该是一个超类(也许是抽象类)。“吸血鬼”类可以实现“致命”以保持其致命行为。此外,“吸血鬼”是“怪物”,所以“怪物”也应该是一个类。“Vampire”类还可以实现一个名为“Dangerous”的接口,以保持其危险行为。如果我们希望创建一个名为“BigRat”的新怪物,它是危险的,但不是致命的,那么我们可以创建一个“BigRat”类,它扩展了“Monster”并实现了“Dangerous”。
上述内容不会实现与使用“Vampire”作为接口相同的输出(在链接中描述)吗?我看到的唯一区别是,使用类继承和保留“IS-A”关系可以消除很多混乱。然而,这并没有被遵循。这样做有什么好处?
即使你想让一个怪物分享吸血鬼的行为,你也总是可以重新定义物体的表示方式。如果我们想要一种名为“VeryMildVampire”的新型吸血鬼怪物,并且我们想创建一个名为“Chupacabra”的类似吸血鬼的怪物,我们可以这样做:
“吸血鬼”类扩展 “怪物” 实现 “危险”、“致命”、“吸血鬼”
“非常吸血鬼”类扩展“吸血鬼”类
“丘帕卡布拉”类扩展“怪物”实现“吸血鬼”
但我们也可以这样做:
“VeryMildVampire”扩展 “Monster”实现危险,致命,吸血鬼
“Chupacabra”扩展“Monster”实现危险,吸血鬼
这里的第二种方法创建了一个“吸血鬼”接口,这样我们就可以更容易地定义一个相关的怪物,而不是创建一堆定义吸血鬼行为的界面(如第一个例子)。但这打破了IS-A的关系。所以我很困惑...