我有一个超类动物,有两个子类,猫和狗。狗和猫都需要有特定的说话和移动方法。以下是实现此目的的两种选择:
这些方法中的一种比其他方法更合适吗?我知道如果我有动物的ArrayList,我会写:
ArrayList Animal<allAnimals> = new ArrayList <Animal>():
allAnimals.add(new Dog());
allAnimals.add(new Cat());
//If I override the methods, I can simply go:
for (Animal a: allAnimals) a.move();
//Where as if I implemented the methods, I would not need be able to do this. I would need to cast the animal as its specific animal. e.g. If I knew the animal was a dog.
Dog aDog= (Dog) a;
a.move();
因此,压倒和实施可能会有一些优点和缺点,具体取决于他们使用的情况。其他人可以详细说明吗?
答案 0 :(得分:3)
作为一般经验法则,当且仅当您的扩展类将共享大量行为时,才使用扩展(抽象类)。在这种情况下,可以使用扩展来消除重复代码的需要,这是A Good Thing(TM)。
另一方面,如果您的类只需要具有相同的签名,那么请使用更灵活的接口(例如,您可以实现多个接口,但只能从一个类扩展)
这只是一些通用的建议,因为每个用例都不同。 为了避免扩展的限制,可以使用其他技术,例如,组合:(http://en.wikipedia.org/wiki/Composition_over_inheritance)。
最后但并非最不重要的是,我认为你的代码中有些误。 您可以以完全相同的方式调用基类上的方法,无论它们是从抽象类还是接口继承它们。
答案 1 :(得分:3)
首先,从子类的角度来看,覆盖或实现方法之间没有区别。因此,您编写的代码在所有情况下都将完全相同(在Java中,所有方法都像C ++ virtual
函数一样;调用的方法是被引用的实际类之一。)
因此,决定是定义一个超类,即接口,抽象类或可实例化的类。
如果有意义创建超类(new Animal()
)的对象,则应使用可实例化的类。
抽象类,当没有超类的对象但某些方法的实现将由所有(或几乎所有)子类共享时。
接口,当您只定义合同时,实现留给每个子类。
决定使用哪个问题取决于问题的范围。例如,如果move()
仅表示“更改动物的x,y坐标”,则可能它应该是抽象类中的实现方法。但是如果你必须定义动物的移动方式,那么Animal
会更好一个接口,所以每个子类都定义它。
答案 2 :(得分:1)
一般来说,经验法则是使用接口,如果可以导致Java类可以实现许多接口但只扩展一个类。
只有当几个类有很多共同之处且你希望能够重用相同的代码时,才应该使用扩展(继承)。
顺便说一句,在您提供的代码中,您可以使用:
for (Animal a: allAnimals) a.move();
在您使用接口和继承的情况下。
答案 3 :(得分:1)
在这种情况下,它可能取决于你是否想要一个默认的move()实现,所以Dog和Cat不必提供自己的实现。据推测,move()方法在猫狗之间具有很多共性,因此你可以通过超类中的常见实现获得更好的可重用性。
答案 4 :(得分:1)
//Where as if I implemented the methods, I would not need be able to do this. I would need to cast the animal as its specific animal. e.g. If I knew the animal was a dog.
Dog aDog= (Dog) a;
a.move();
不,你根本不需要这样做。如果Animal
是一个接口而不是一个抽象类,那么为抽象类显示的过程就可以正常工作。
答案 5 :(得分:1)
从概念上讲,抽象类描述了什么是东西,一个界面描述了它的作用。在这种情况下,将Animal作为抽象类是合适的,因为猫或狗是动物。在功能上,选择哪个选项可以产生最少的编码/最干净的类层次结构。
答案 6 :(得分:0)
首先,你有第三个选项,即:有一个界面(比如MoverAndSpeaker;虽然那是一个蹩脚的名字),并且有抽象基类动物&#39; implmenent&#39;它:
static public abstract class Animal implements MoverAndSpeaker {
@Override
public abstract void move();
public abstract void speak();
}
为什么你甚至想要这样的东西?
与此处的一些答案不同,我认为语义一致性是最重要的考虑因素,避免代码重复等问题要么自己解决,要么重视少数。
如果我在你的位置,我将适用的关键标准是:
&#34;是否有移动和说话的物体,这些物体不是动物?&#34;
&#34;所有动物都会移动并说话吗?&#34;
最后,如果所有动物没有任何共同点,那么正如其他答案中所建议的那样,您可能根本不需要动物基类。