是否有任何理由要在类中定义每个方法的抽象类?

时间:2014-12-18 22:31:02

标签: java inheritance

似乎抽象类意味着类的定义不完整,因此无法实例化。

我看到了一些简单的Java代码,它有一个抽象类,定义了所有方法。然后我想知道,为什么他们把它作为抽象类而不是真正的类呢?他们这样做是为了让我们无法从这个抽象类中实例化吗?或者他们从定义所有内容的抽象类中获得其他好处?

7 个答案:

答案 0 :(得分:43)

即使所有方法都有默认实现,但这些实现可能在应用程序的上下文中实际上并非有意义。这些方法可能只进​​行内部簿记,而实际有用的实现必须由派生类提供,派生类执行它需要做的事情,然后调用超类方法。

然而,这只是猜测。你必须展示一个实际的例子来说明这个设计可能是什么原因。

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

  • 有些是可见的,所以我的基础类获得draw()方法。但是可能会有一些看不见的对象,比如根本没有出现的触发区域,所以我将它作为基类中的无操作实现。

  • 有些人在碰到某些东西时会做某事,所以每个人都会得到一个collide(other)方法。但有些人在碰撞时就不会做任何事情,就像纯粹的视觉粒子效果一样,所以我也在基类中提供了无操作。

  • 有些人会在每场比赛中做点什么,所以他们得到update()方法。但有些物体,如墙壁,可能根本不会做任何事情。所以我也为此提供了无操作。

那么,当我有一个看不见的物体,不做任何事情而且不与任何东西互动时,我该怎么办?在游戏中没有理由这样做。所以我做了这个基础课abstract理论上你可以实例化它,因为所有方法都有一个实现,但几乎你没有理由这样做,当你尝试时,你误解了我的游戏引擎是如何工作的。

答案 1 :(得分:22)

一个典型的用例是创建适配器类。考虑一个回调接口,您可以在其中收到10个不同事件的通知,但通常只对其中一些事件感兴趣。使用适配器类,您可以提供空实现,这样实际的回调只需要在扩展适配器后实现那些感兴趣的方法。通过使适配器抽象化,您表达了这样一个事实:实例化适配器本身是没有意义的,因为它没有任何用处。

从Java 8开始,您将不再实现此类适配器,而是使用默认方法作为接口。

答案 2 :(得分:11)

是的,有。有时候你知道你正在创建一个抽象类 - 一个必须从中派生出来才能产生任何实际意义的类,但你想为所有方法提供一个默认实现。这并没有发生太多,但它确实发生了。

更新: 我刚才有这样的案子。我正在录制各种用户生成的事件。每个事件都有一个TimeSpan和一个描述,它们都有其他的东西。我创建了一个基本事件类:

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编写,我本可以做同样的事情)

答案 3 :(得分:7)

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

E.g。

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
    }

}

答案 4 :(得分:4)

如果一个Java类被声明为abstract而且声明了它的所有方法,那么它们就是这样做的,所以它不能被实例化,尽管它可能是子类。

"抽象类不能被实例化,但它们可以被子类化。" 见这里:https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

答案 5 :(得分:4)

您可能有一些课程在您的应用程序的上下文中没有意义,但他们在设计中做了。 一个愚蠢的例子: 抽象类动物,实现生而死。你不想要一个"动物"。你想要一只狗。 这样您就不必重复添加每个类的代码。现在你可以拥有狗,猫或任何你想要的东西,这是一个很好的理由,无论如何它很难找到。

答案 6 :(得分:3)

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

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

然后,当实现新的派生类时,您有一个可运行的实现,然后您可以选择覆盖这些方法,以便为该派生实例自定义行为。

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转到几个不同的数据服务,以获取有关该特定项类型的信息,但仍使用一些基本实现默认值。这涵盖了接下来的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
    }
}