因此,在尝试理解抽象类时,仍有一件事我感到困惑。你什么时候想要声明它的抽象类的对象类型。例如
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
}
}
通常,我只会实现玩家类型的玩家对象。但是,我已经看到抽象类用作新对象的变量类型。你什么时候选择这样做?谢谢!
答案 0 :(得分:2)
每当你需要变量作为抽象类的一个实例时,你就会这样做,但是并不真正关心具体类型是什么(并且不希望其余的代码假设一个特定的子类用来)。例如:
GameObject[] gameObjects = new GameObject[] {new Menu(), new Player()};
drawAll(gameObjects);
...
private void drawAll(GameObject[] gameObjects) {
for (GameObject gameObject : gameObjects) {
gameObject.draw();
}
}
抽象类型通常用作返回类型(因为您不希望调用者知道返回的具体类型:它可能稍后更改,或者可能根据配置的参数而变化)。
它也经常用作方法参数类型,因此该方法可以接受抽象类型的任何子类的参数并以多态方式使用它。
当然,作为一个数组/集合类型,能够在一个唯一的集合中存储多个子类的实例。
答案 1 :(得分:2)
假设您要添加功能以使特定GameObject
不可见。原始实现看起来像:
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实现。您可以稍后将其更改为LinkedList
,而不会更改上述任何内容。
如果您没有找到合理的情况,这样的声明对您的抽象有意义,那么它可能是以下情况之一的症状:
makeInvisible
示例在您的特定情况下,该抽象类的设计并不是特别好。
首先,它使main()
方法对其所有子类都可见,并且没有理由要在main
或Player
的范围内使用Menu
其次,它更适合作为接口(可能是Drawable
),因为它所做的就是定义draw
方法的签名。这种变化会使其多态性能力变得更加明显,因为您应该能够找到将对象视为仅仅Drawable
的对象,这应该可以回答您的问题。
答案 2 :(得分:1)
我们假设您有一个抽象的Animal
课程,其中包含eat()
,sound()
等方法。
您可以创建扩展此Animal
课程的课程,让我们说Dog
和Cat
。
如果抽象类中有抽象方法(这不是强制性的),那么您需要在extends Animal
的每种类型中实现该方法。
如果方法不是抽象的,如果你想让它做一些与主类不同的东西,你仍然可以覆盖它。
如果您仍然不完全理解,请尝试播放此视频https://www.youtube.com/watch?v=TyPNvt6Zg8c。