Java中的接口和抽象类与示例混淆

Java中的接口和抽象类与示例混淆,java,oop,interface,abstract-class,Java,Oop,Interface,Abstract Class,我很难理解何时使用接口而不是抽象类,反之亦然。此外,我还不知道何时用另一个接口扩展一个接口。很抱歉发了这么长的帖子,但这让人很困惑 创建形状似乎是一个流行的起点。假设我们想要一种建模2D形状的方法。我们知道每个形状都有一个面积。以下两种实现之间的区别是什么: 带接口: public interface Shape { public double area(); } public class Square implements Shape{ private int length

我很难理解何时使用接口而不是抽象类,反之亦然。此外,我还不知道何时用另一个接口扩展一个接口。很抱歉发了这么长的帖子,但这让人很困惑

创建形状似乎是一个流行的起点。假设我们想要一种建模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”三角形。一个三角形是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;
    }
}
在我看来,这两种方法都有效。但是什么时候你会用一种方法而不是另一种?与抽象类相比,使用接口来表示不同的三角形有什么优势吗?尽管我们使形状的描述复杂化,但使用接口和抽象类似乎仍然是等价的

接口的一个关键组件是,它可以定义可以跨无关类共享的行为。因此,一个可飞行的界面将出现在飞机类和鸟类类中。因此,在这种情况下,显然首选接口方法

此外,要构建混乱的接口,扩展另一个接口: 在决定什么是接口时,什么时候应该忽略“IS-A”关系? 例如:

为什么“verybadvanpire”应该是一个类,“Vampire”应该是一个接口?“verybadvanpire”是一个“吸血鬼”,所以我的理解是“吸血鬼”应该是一个超类(可能是抽象类)。“吸血鬼”类可以实现“致命”以保持其致命行为。此外,“吸血鬼”是“怪物”,所以“怪物”也应该是一个类。“吸血鬼”类还可以实现一个名为“危险”的接口,以保持其危险行为。如果我们希望创建一个名为“大老鼠”的新怪物,它是危险的但不是致命的,那么我们可以创建一个“大老鼠”类,它扩展了“怪物”并实现了“危险”

上面提到的不是与使用“吸血鬼”作为接口(在链接中描述)实现相同的输出吗?我所看到的唯一区别是,使用类继承和保留“is-A”关系可以消除很多混淆。然而,这并没有得到遵守。这样做的好处是什么

即使你想让怪物分享吸血鬼的行为,你也可以重新定义对象的表示方式。如果我们想要一种叫做“VeryMildVampire”的新型吸血鬼怪物,我们想要创造一种叫做“Chupacabra”的吸血鬼怪物,我们可以这样做:

“吸血鬼”类扩展了“怪物”实现了“危险的”、“致命的”、“吸血的”
“VeryMildVampire”类扩展了“吸血鬼”类
“Chupacabra”类扩展了“怪物”实现“吸血鬼”

但我们也可以这样做:

“VeryMildVampire”扩展了“怪物”装备危险、致命、吸血鬼的功能
“Chupacabra”扩展了“怪物”工具的危险性,吸血鬼


第二种方法是创建一个“吸血鬼”接口,这样我们就可以更容易地定义一个相关的怪物,而不是创建一堆定义吸血鬼行为的接口(如第一个示例)。但这打破了IS-A关系。所以我很困惑…

当您想要使一个或多个方法不抽象时,请使用抽象类


如果你想保持所有的抽象,使用一个界面。

你的形状示例很好。我是这样看的:

只有当有共享的方法或成员变量时,才有抽象类。对于
Shape
示例,您只有一个未实现的方法。在这种情况下,请始终使用接口

假设你有一门动物课。每只动物都会记录它有多少四肢

public abstract class Animal
{
    private int limbs;
    public Animal(int limbs)
    {
        this.limbs = limbs;
    }

    public int getLimbCount()
    {
        return this.limbs;
    }

    public abstract String makeNoise();
}
因为我们需要跟踪每个动物有多少肢体,所以在超类中包含成员变量是有意义的。但是每种动物都会发出不同类型的噪音

因此,我们需要使它成为一个抽象类,因为我们有成员变量、实现的方法以及抽象方法

对于第二个问题,你需要问自己这个问题

三角形总是一个形状吗

如果是这样,则需要从形状界面延伸三角形


总之,在第一组代码示例中,选择接口。对于最后一组,选择第二种方式

你这里有很多问题。但我认为基本上你是在问接口和抽象类

对于接口,您可以拥有实现多个接口的类。但是,如果您想将其用作API,则该接口是不持久的。一旦发布了接口,就很难修改接口,因为它会破坏其他人的代码

对于抽象类,您只能扩展一个类。然而,抽象类对于API来说是持久的,因为您仍然可以在更高版本中进行修改,而不会破坏其他人的代码。同样使用抽象类,您可以有预定义的实现。考试
class Vampire extends Monster implements Dangerous, Lethal, BloodSuckable
       abstract class Dog {}

       class Breed1 extends Dog {}

       class Breed2 extends Dog {}
     interface Animal {
         void eat();
         void noise();
     }

     class Tiger implements Animal {}

     class Dog  implements Animal {}