【问题标题】:Java implementation of Polymorphism, casting and method overriding in Game design游戏设计中多态性、强制转换和方法覆盖的 Java 实现
【发布时间】:2017-06-03 09:43:47
【问题描述】:

注意:这是我的问题的概念版本。我关于这些概念的应用的实际问题显示在此块下方。


我试图弄清楚一个对象何时被认为是它自己的类或类的超类的实例。考虑以下超类 Animal 和子类 Seahorse:

import java.util.List;
import java.util.ArrayList;
public class Animal
{
    public static void main(String[] args)
    {
        Animal a= new Animal();
        /*1. This line prints a's class*/
        System.out.println(a.getClass());

        List<Animal> animals= new ArrayList<Animal>(1);
        animals.add(new Seahorse(1));
        //2. Let's see what happens here
        animals.get(0).printClass();

        for(Animal e : animals)
        {
            e.printClass(); //3 This is an overriden method
            //e.printThisClass(); Compile Time error;
            //4. Note this method only exists in subclass
        }
        Animal hiahiahia = new Seahorse();
        hiahiahia.printClass(); //5. Lets see what happens
        hiahiahia.printThisClass(); //6. 
    }
    public void printClass()
    {
    System.out.println("Animal");
    }
}

public class Seahorse extends Animal
{
    private int y;
    public Seahorse(int a)
    {
        this.y=a;
    }
    public void printClass()
    {
        System.out.println("Seahorse");
    }

    public void printThisClass()
    {
        System.out.println("Seahorse");
    }
}

输出如下所示:

class Animal  //1.
Seahorse      //2.
Seahorse      //3.
Seahorse      //5.

可以看到,虽然 Seahorse 对象存储在 Animal 对象或列表中,但多态性导致 Seahorse 方法被调用。

但是,当我尝试调用一个名称仅存在于伪装成 Animal 对象的 Seahorse 对象的子类中的方法时,编译会引发错误。

问题: 多态性是否仅在方法覆盖时才有效?有没有什么时候

 Animal animal = new Seahorse(1);

导致动物只被视为动物(不是海马)?

有什么区别

 Animal animal = new Seahorse();
 animal.printThisClass();

((Seahorse)animal).printThisClass();

最后,什么时候应该使用强制转换?


我正在开发一个 2d 游戏并创建了以下类:

public class Entity
{
}

public class Character extends Entity
{
  //With bunch of extra fields and methods
}

我还有一个控制器类,它有两个字段:

private List<Entity>;
private List<Character>;

我将它们分开是因为实体(在本例中为箭头、项目符号)仅与字符发生冲突,而不会与其他实体发生冲突。 这就是问题所在:我还有一个渲染方法可以绘制我所有实体的 BufferedImage。现在为了使图表有意义,应按 Y 值的升序呈现实体。(即从最远到最近)。但是,这需要将所有角色和实体放在同一个集合中......

问题是:我应该将它们分开吗?如果我将它们放在同一个 List 中,那会不会因为无法区分 Entities 中的字符而引起混淆?

谢谢:)

【问题讨论】:

  • 我强烈建议您退后一步,密切关注interface - 例如Cat 可以是CollideAnimalRenderableMovable 和可能还有很多其他的东西。 interface 允许您更好地描述“意图”以及混合和匹配组合,在大多数情况下,您可能无法单独使用扩展。这也意味着Cat 可以驻留在用于管理它实现的任何interfaces 的任何集合中。稍微巧妙地使用 Java 8 的 Streams,您可以拥有一个可以过滤的“东西”主列表
  • Rock 可以在CollideRenderable 中使用,但仅此而已:P。尽可能避免对对象/实体的底层实现做出假设
  • 如果你必须投,那你就错了。
  • 你要么了解多态性,要么不了解。铸造是你做错了的标志。您应该有一个通用接口,每个实现者都有自己的实现风格。您遍历接口引用类型的列表。当您调用公共方法时,每个具体的子类型都会做正确的事情。
  • 我以为您有一个列表并使用 Java 8s Stream 支持来过滤它以满足您的需求。在大多数情况下,你会有一个“更新”通道,它会执行移动、碰撞和其他生命周期处理,然后你会做一个单独的绘制通道,因为更新通道可能会改变绘制的内容和时间,所以你不要不想一次通过它们

标签: java list animation polymorphism overriding


【解决方案1】:

第一个问题的答案:

有什么区别

动物 = new Seahorse();动物.printThisClass();和

((海马)动物).printThisClass();

没有区别。 当您将该动物投向海马时,它允许您访问海马的方法。例如,如果 Seahorse 类有一个名为 blowBubble() 的方法,如果你使用了 animal.blowBubble()(假设animal 定义如上),那么它会给你一个错误,因为 Animal 类没有一个名为 blowBubble() 的方法。

但是,当您通过 ((Seahorse)animal) 将动物变量转换为 Seahorse 时,您是在说我知道这种动物是海马,所以请允许我使用 Seahorse 的方法。

Animal animal = new Seahorse();
animal.method();
((Seahorse)animal).method(); // calls the exact same method even if it was overriden

但是,如果你这样做,你会注意到

Animal animal = new Animal();
((Seahorse)animal).blowBubbles();
((Seahorse)animal).method();

每次您尝试施放它时,它都会抛出 ClassCastException,因为 Animal 无法转换为 Seahorse。但是,因为 Seahorse 始终是动物,所以您可以在 Seahorse 实例上调用任何动物方法。

Seahorse seahorse = new Seahorse();
seahorse.methodInAnimalClass();

对于您的下一个问题,是否有两个单独的字符和实体列表完全取决于您。由于您需要执行一个简单的排序算法来确定谁的 y 位置最大或最低,所以这可能无关紧要。

您始终可以创建一个名为 getAllEntities() 的方法,该方法返回一个组合实体和字符的新列表,然后对该列表进行排序并呈现它们。

就像 cmets 所说,您还应该查看接口,但我不建议创建大量接口。我认为从简单开始是可行的方法,但是,随着您的游戏变得更高级,您可能需要考虑实施它们。

【讨论】:

  • 明白。但是,如果我想将 \\Animal animal = new Seahorse() \\ 或 \\Seahorse seahorse = new Seahorse() 放入 List 或 List,那会有什么不同吗?第一个对象不能放入第二个列表,对吗?您对组合列表的建议听起来可行,但我可以将 List 转换为 List 吗?谢谢。
  • 是的,您不能将动物放入海马列表中,因为它不是海马。做 Animal animal = new Seahorse() 或 Seahorse seahorse = new Seahorse() 的唯一区别是,如果您想访问 Seahorse 类中定义的方法或将其添加到列表中,或将其传递给另一个方法,您将拥有铸造它。您不能将 List 转换为 List 但您可以在这里查看link 组合列表后,您应该有一个 List
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多