为什么不覆盖而不是使用抽象类?

时间:2013-12-26 19:44:18

标签: java abstract-class override

这对许多人来说可能是一个简单的问题,但让我很困惑。我从Kathy Sierra中选择了一个示例,它展示了抽象类的实用性,但我无法理解抽象类的整体重要性。

示例 我们有一个抽象类Car和抽象方法 - power()& topSpeed()。这些方法在子类 BMW Volkswagen Audi 中实现。

我的问题是 - 为什么我们首先需要抽象类Car来定制每种车型的方法?为什么不在这些汽车的任何一种汽车中使用这两种方法,宝马和其他两种 - 大众汽车和奥迪 - 可以简单地改写这些方法吗?

6 个答案:

答案 0 :(得分:6)

通过使方法抽象,意味着人们必须实现它。你需要人们这样做,人们不可能忘记这样做,因为如果他们这样做就无法编译。

@override注释存在的原因非常相似,通过将方法标记为@override,如果(例如)键入方法名称错误且实际上没有覆盖某些内容,则会出现错误。

在很多方面,抽象类是接口和普通类之间的一半 - 它定义了你需要做什么才能以与接口相同的方式使用它,但它也为你处理了一些实现。 / p>

类只能扩展另一个类。他们可以实现任意数量的接口。

例如,MotorVehicleCarMotorbike可能会继承Train,但您可能会Steerable实现Car接口},MotorbikePedalbike

回答评论中的问题:

  

如果有一个接口“I”的方法m()由类“A”实现而另一个类“B”想要访问方法m(),那么接口的需求是什么。我们可以简单地在A类中实现该方法吗?

您可以 - 但另一方面,如果课程B想要在课程m()和课程A(其中A和C课程)中访问方法C不继承彼此或包含m()的公共类,那么这样做的方法是指定一个公共接口I,而类B使用接口类型,I,而不是类型A和C。

还要记住,可以在包和库之间使用接口。例如, Listener 策略模式大量使用接口。当Java开发人员编写JButton(例如)时,ActionLstener被指定为接口,以便为将来使用JButtons的人提供最大的灵活性。

答案 1 :(得分:1)

  

为什么不在这些汽车的任何一种汽车中使用这两种方法,宝马和其他两种 - 大众汽车和奥迪 - 可以简单地改写这些方法吗?

这不需要VolkswagenAudiBMW继承吗?这不正确,因为那些不是宝马。

抽象基类及其抽象方法构成了一种继承对象必须实现的契约。没有具体的Car这样的东西不是更具体的类型。但所有具体类型都有共性。摘要Car强制执行这些共性,允许在需要时将特定类型视为Car的通用实例。

例如,如果您的代码需要Car,它将调用Drive()方法,那么该代码不关心{{1}的种类它得到了。它将Car任意Drive()。所以它接受一个抽象类型,以便可以使用任何实现该类型的东西:

Car

如果不执行合同,静态类型和编译语言将无法保证对象上存在UseACar(Car car) { car.Drive(); } // elsewhere BMW myCar = new BMW(); UseACar(myCar); 。您需要为每种可能类型的汽车创建.Drive()方法,每种方法都接受不同的类型。使用这样的多态性允许您创建一个更通用的方法,该方法适用于抽象类型的任何实例。

答案 2 :(得分:0)

这样您就可以编写处理Car的代码而不知道它是什么类型的汽车:

public void PrintTopSpeed(Car car)
{
    System.out.println("This car's top speed is " + car.topSpeed());
}

如果Car类没有定义topSpeed(),则此代码将无法编译。您必须为每个BMW,Volkswagen,Audi等派生类提供不同版本的打印功能。这可能是面向对象编程中最基本的概念,所以你真的需要掌握它。基类允许对象共享共同的行为,并允许编写代码以使用该行为,而无需了解它正在处理的特定类型的对象。

答案 3 :(得分:0)

多态性就是答案。如果你在抽象类中没有方法power()和topSpeed(),你就不能这样做:

List<Car> cars;
cars.add(new Porshe());
cars.add(new Ford());

for(Car car : cars){
    System.out.println(car.topSpeed());
}

如果您的子类中只有自定义方法,那么您必须自己处理很多事情。

答案 4 :(得分:0)

这称为抽象。抽象类中的方法被认为是协议,因此汽车制造商不应该违反。

答案 5 :(得分:0)

当原始程序员/架构师希望允许某些基类的自定义行为并确保消费程序员实现所需的方法时,抽象是很棒的。