Java 何时使用抽象类作为类型

Java 何时使用抽象类作为类型,java,inheritance,abstract-class,instantiation,Java,Inheritance,Abstract Class,Instantiation,因此,在试图理解抽象类的同时,有一件事我仍然感到困惑。您何时需要声明其抽象类的对象类型。比如说 public abstract class GameObject { public abstract void draw(); public static void main(String[] args) { GameObject player = new Player(); Menu menu = new Menu(); } } public class Player extends

因此,在试图理解抽象类的同时,有一件事我仍然感到困惑。您何时需要声明其抽象类的对象类型。比如说

public abstract class GameObject
{
 public abstract void draw();
 public static void main(String[] args)
 {
 GameObject player = new Player();
 Menu menu = new Menu();
 }

}
public class Player extends GameObject
{
 override 
 public void draw()
 {
 // Something
 }

}
public class Menu extends GameObject
{
 override 
 public void draw()
 {
 // Something
 }
}

通常,我只是实例化一个玩家类型的玩家对象。但是,我看到抽象类被用作新对象的变量类型。你什么时候会选择这样做?谢谢

每次需要变量作为抽象类的实例时,您都会这样做,但并不真正关心具体类型是什么(也不希望代码的其余部分假定使用了特定的子类)。例如:

GameObject[] gameObjects = new GameObject[] {new Menu(), new Player()};
drawAll(gameObjects);

...

private void drawAll(GameObject[] gameObjects) {
    for (GameObject gameObject : gameObjects) {
        gameObject.draw();
    }
}
抽象类型通常用作返回类型(因为您不想让调用方知道返回的是什么具体类型:它可能会在以后更改,也可能会根据配置的参数而有所不同)

它还经常用作方法参数类型,因此该方法可以接受抽象类型的任何子类的参数并以多态方式使用它


当然,作为一种数组/集合类型,可以在一个唯一的集合中存储多个子类的实例。

假设您有一个抽象的
Animal
类,其方法包括
eat()
sound()

您可以创建扩展这个
动物
类的类,比如

如果抽象类中有抽象方法(这不是强制性的),则需要在扩展Animal的每个类型中实现该方法

如果该方法不是抽象的,如果希望它执行与主类不同的操作,仍然可以重写它


如果您仍然不完全理解,请尝试此视频。

说您想添加功能以使特定的
游戏对象不可见。原始实现看起来像:

void makeInvisible(GameObject object) { ... }
这个方法应该适用于任何类型的
GameObject
(并且能够使它们都不可见——或者如果传递了“错误”类型的对象,它可以抛出
IllegalArgumentException

然而,你的问题似乎特别关注这种声明:

GameObject gameObject = new Player(); // why on earth would you do this -- you wonder
首先想想你经常看到以下情况:

List<String> stringList = new ArrayList<>();
List-stringList=new-ArrayList();
然而,这被推荐为最佳实践,因为代码的其余部分不应该知道所选择的特定列表实现。稍后,您可以将其更改为
LinkedList
,而无需更改上面那一行以外的任何内容

如果您找不到这样的声明对您的抽象有意义的合理场景,那么这可能是以下情况之一的症状:

List<String> stringList = new ArrayList<>();
  • 您不愿意使用多态性:也就是说,您希望为每个子类型定义特定的逻辑,并且永远不要“一般地”处理它们——就像上面的
    makeInvisible
    示例中那样
  • 你的抽象并没有给你带来多少好处;换句话说,它本身是不可用的,您可能应该重新考虑您的设计
在您的特定情况下,抽象类的设计不是特别好

首先,它使
main()
方法对其所有子类都可见,并且没有理由希望
main
Player
菜单的范围内


其次,它更适合作为接口(
Drawable
),因为它所做的只是定义
draw
方法的签名。此更改将使其多态性功能更加明显,因为您应该能够发现需要将对象视为可绘制对象的位置,这将回答您的问题。

您可能会将其视为参考类型,但是你从来没有见过一个被实例化为该类型的实现。我想这可能就是我的意思,但是什么时候这样做才是明智的呢@如果有一个方法根据参数返回其中一个子类,该怎么办?然后返回接口类型(很可能是抽象类型)。@johnwoolstock Smart要做什么?是否将抽象类用作引用类型?任何时候都可以传递抽象类的非特定实现。这种情况基本上一直都在发生,尽管在接口中可能更频繁,例如,
List foo=new ArrayList()谢谢!现在更有意义了。