是否有任何理由让类中的每个方法都有一个抽象类?

看来抽象类意味着类的定义不完整,因此不能被实例化。

我看到一些简单的Java代码,它具有抽象类,并定义了所有的方法。 那么我想知道,为什么他们把它当成抽象类而不是真正的类呢? 他们是否这样做,所以我们不能从这个抽象类实例化? 或者他们从定义一切的抽象类中获得其他好处?

尽pipe所有的方法都有一个默认的实现,但是这些实现在应用的上下文中并没有实际意义 。 这些方法可能只做内部簿记,而实际有用的实现必须由一个派生类提供,派生类完成它需要做的事情,然后调用超类方法。

不过,这只是猜测。 你将不得不展示一个实际的例子来说明这个devise的原因。

举一个例子,我们来看一个简单的游戏引擎。 我有很多不同的GameObject在我的游戏中。

  • 有些是可见的,所以我的基本类得到一个draw()方法。 但是可能会有一些看不见的触发区域,所以我把它作为基类中的一个禁用对象来实现。

  • 有些人在碰到某物时会做某些事情,所以每个人都会collide(other)一个collide(other)方法。 但是当它们碰撞得像一个纯粹的视觉粒子效果时,有些没有做任何事情,所以我也在基类中提供了一个no-op。

  • 有些人在每个游戏中都会做点什么,所以他们得到一个update()方法。 但是有些物体,比如墙,根本就不能做任何事情。 所以我也提供了一个禁止这个。

那么当我有一个看不见的东西时,我该怎么办?它本身不做任何事情,也不与任何东西相互作用? 没有理由在游戏中有这个。 所以我把这个基础课abstract理论上你可以实例化它,因为所有的方法都有一个实现,但是实际上你没有理由这么做,而当你尝试时,你误会了我的游戏引擎的工作方式。

一个典型的用例是创build一个适配器类 。 想想一个callback界面,你可以通知10个不同的事件,但通常只对其中一些事件感兴趣。 使用适配器类,您可以提供空实现,使得实际的callback只需要在扩展适配器之后实现那些感兴趣的方法。 通过使适配器抽象化,您expression了这样一个事实:实例化适配器本身是没有意义的,因为它没有任何用处。

从Java 8开始,您将不再使用这种适配器,而是使用接口的默认方法

就在这里。 有时候你知道你正在创build一个抽象类 – 一个必须从实际意义上派生出来的类,但是你想为所有的方法提供一个默认的实现。 这不会发生很多,但确实发生了。

更新:我刚刚有这样的情况。 我正在logging各种用户生成的事件。 每个事件都有一个TimeSpan和一个Description,而且他们都有其他的东西。 我创build了一个基本事件类:

 public abstract class BaseEvent { public TimeSpan EventTime {get; private set;} public string Description {get; protected set;} public BaseEvent(TimeSpan time, string desc) ... } 

当然,这是C#而不是Java,但是我用Java编写了这个东西,我会做同样的事情)

你可以有一个抽象类来实现几个接口。 您不需要在抽象类中实现这些方法,但是您需要在抽象类的子类中实现它们。

例如

 public interface MyInterface{ void hello(); } public abstract class Clazzy implements MyInterface { //I need not have the interface method. } public class MySubclass extends Clazzy { @Override public void hello() { // I need to be here } } 

如果一个Java类被声明为抽象的,但是它的所有方法都被声明了,那么他们就这么做了,所以它不能被实例化,尽pipe它可能是子类的。

“抽象类不能实例化,但可以分类。” 请参阅https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

你可能有一些在你的应用环境中没有意义的类,但是他们在devise中做了。 一个愚蠢的例子:抽象类动物,实现生而死。 你不想要一个“动物”。 你想要一只狗。 这样你不必重复你添加的每个类的代码。 现在你可以有狗,猫或任何你想要的,这将是一个很好的理由,无论如何这很难find。

我看到这个问题已经标记了答案,但是我想提供另一个替代解释。

这种代码的另一个原因是为抽象类的所有派生类提供基本的实现。

然后,在实现新派生类时,您将拥有一个可运行的实现,然后您可以select覆盖该方法以便为该派生实例自定义行为。

BaseItemBuilder ,它是抽象的,并基于一个通用参数(如ItemNumber)提供数据访问逻辑。

(对不起,C#代码,但这个问题几乎只是编程理论而不是关于特定的语言)

 public abstract class BaseItemBuilder { /*I don't want anyone using this directly but I do want the base specification*/ public virtual void GetInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetItemInfo(itemNumber); //project values on to internal representation of item } public virtual void GetMoreInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetMoreItemInfo(itemNumber); //project values on to internal representation of item } public virtual void GetEvenMoreInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetEvenMoreItemInfo(itemNumber); //project values on to internal representation of item } public virtual void GetYetMoreInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetYetMoreItemInfo(itemNumber); //project values on to internal representation of item } } 

然后你可以派生一个使用基本实现的NormalItemBuilder 。 这占了你正在跟踪的项目的80%。

 public class BaseItemBuilder { /*I use the base implementation!*/ } 

然后,您派生一个SpecialType1ItemBuilder ,它转到几个不同的数据服务来获取有关该特定项目types的信息,但仍使用一些基本实现默认值。 这包括接下来的10%。

 public class SpecialType1ItemBuilder { /*I don't want anyone using this directly but I do want the base specification*/ public override void GetInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetType1ItemInfo(itemNumber); //project values on to internal representation of item } public override void GetYetMoreInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetYetMoreType1ItemInfo(itemNumber); //project values on to internal representation of item } } 

然后你派生出一个`SpecialType2ItemBuilder',去到另一组零星的数据服务来完成该项目的图片。 这个覆盖了另一套不同于Type2ItemBuilder的方法。 这涵盖了你最后的10%。

 public class SpecialType2ItemBuilder { /*I don't want anyone using this directly but I do want the base specification*/ public override void GetInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetType2ItemInfo(itemNumber); //project values on to internal representation of item } public override void GetMoreInfoAboutItem(int itemNumber){ var infoModel = _infoDataService.GetMoreType2ItemInfo(itemNumber); //project values on to internal representation of item } }