我想了解为子对象设置父引用的用例。 示例:Dog类扩展了Animal类。 (没有接口,请记住) 我通常会像这样创建一个Dog的对象:
Dog obj = new Dog();
现在,由于Dog是Animal的一个子类,因此它已经可以访问所有Animal的方法和变量。然后,这有什么不同:
Animal obj = new Dog();
请提供正确的用例以及其使用的代码段。没有关于多态性的理论文章'或者'编码到接口'请!
代码:
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Dog();
Dog obj2 = new Dog();
obj1.shout(); //output is bark..
obj2.shout(); //output is bark..
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Dog extends Animal{
public void shout(){
System.out.println("bark..");
}
}
class Lion extends Animal{
public void shout(){
System.out.println("roar..");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh");
}
}
两种情况的输出相同。那么我们为什么要设置对子对象的父引用呢?
答案 0 :(得分:8)
让我编写一些时间。
List<String> list = new ArrayList<String>;
list.doThis();
list.doThat();
等等。我疯了。我想使用LinkedList
代替ArrayList
List<String> list = new LinkedList<String>;
list.doThis();
list.doThat();
是的,我必须只改变声明部分。无需触摸我的所有代码。感谢对接口和超类的编程。
答案 1 :(得分:3)
一般来说,你会了解java cast / oop概念。
Dog
是Animal
的一种类型,因此您可以将其分配给动物。
但您无法将Animal
分配给Dog
。因为它可以是任何其他动物,如Cat
。如果您确定该对象为Dog
,则可以将其结算为Animal
。如果Animal
的类型为Dog
,那么您就无法神奇地投射到Goat
。
答案 2 :(得分:2)
这是一个原则的实现,说 -
编程到接口,而不是实现。
例如,如果您设计一个方法来接受Animal
类型的引用,那么将来您可以轻松地将= Cat
实现传递给它(当然提供{{1} }}是Cat
的子类型。
这意味着 -
Animal
比 -
更灵活public void doSomethingWithAnimal(Animal animal) {
// perform some action with/on animal
}
因为对于第一种方法,您可以轻松地执行类似的操作 -
public void doSomethingWithAnimal(Dog d) {
// your code
}
如果您决定创建新的doSomethingWithAnimal(new Cat());
类型,则继承自Cat
。
答案 3 :(得分:1)
虽然有一些好的答案(在&#34; meh&#34;之中),但似乎没有人能接受你。也许他们太理论化或包含你不感兴趣的细节。所以另一个尝试:
对于您描述的示例,无关紧要。如果你真的只有像
这样的双线方法void doit()
{
Animal x = new Dog();
x.shout();
}
然后你也可以写
void doit()
{
Dog x = new Dog();
x.shout();
}
这将不直接劣势。
甚至可以概括这句话:对于仅使用本地的参考,这无关紧要。当您声明方法中的引用时,仅在此方法中使用此引用,并且不将其传递给其他方法,那么将其声明为Animal
而不是Dog
并不是直接的优势。你可以两个。
即使你对此不感兴趣,我也不能忽略它:
...使用父类型是最佳实践的一部分:
您应该始终使用足以满足您要求的
的最小特定类型
这有各种技术原因,涉及抽象,概括,灵活性,多态性的应用,甚至可以将其称为某种类型的卫生&#34;。
明确也指的是引用仅在本地使用的情况:如果您不想调用特定于Dog
类型的方法,只想调用Animal
类中的方法,然后你应该通过将变量声明为Animal
来明确这一点 - 只是因为它是你需要的最不具体的类型。因此,在这些情况下使用类型Animal
存在间接优势 - 即很明显以下代码将仅使用Animal
类的方法,并且< Dog
类的em> none 。
可以继续进行,并在此处进一步说明进一步的理由,用例和技术细节。但为此,您可以参考其他答案,或一些中级或高级教科书和教程。
答案 4 :(得分:1)
好。我想我得到了答案。
public class Polymorphism {
public static void main(String[] args){
Animal obj1 = new Horse();
Horse obj2 = new Horse();
obj1.shout(); //output is neigh..
obj2.shout(); //output is neigh..
obj1.winRaces(); /*But this is not allowed and throws compile time error,
even though the object is of Animal type.*/
}
}
class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
class Horse extends Animal{
public void shout(){
System.out.println("neigh..");
}
public void winRaces(){
System.out.println("won race..");
}
}
因此,当我们对子类对象使用父引用时,我们无法使用该对象访问子类中的任何特定方法(父类中不存在)。
答案 5 :(得分:0)
当你从这样一个简单的例子开始时,你看不到任何好处,因为你已经将变量与它将保持的实际对象类型紧密耦合。
只有当您考虑方法声明时,多态性才会出现,其中参数是方法实现所需的最小特定类型:然后您可以使用任何子类型调用它,并且该方法将知道如何处理它,即使它不知道实际的对象类型。这是Liskov类型可替代性的本质。
所以想象你有一个方法
int getAge(Animal a) {
return Days.toYears(currentDate() - a.dateOfBirth());
}
该方法适用于任何Animal
,即使是在定义方法后定义的那些。
但是,如果您碰巧理解了上述内容,那么请专门询问 为什么会写
Animal a = new Dog();
然后它仍然经常有意义:你事先承诺,你不会引用实例的任何特定于狗的方面。通常你会看到
List<String> strings = new ArrayList<>();
在这种情况下,我们知道代码的其余部分并不依赖于ArrayList
作为列表实现的特定选择。这比上面描述的差异要小得多,但它是简洁,安全和习惯的结合,使它坚持下去。
答案 6 :(得分:0)
当您希望您正在编写的代码针对Animal接口而不是Dog实现时,就会出现这种情况。以这种方式创建对象可以使您的代码在长期内更加健壮。
我经常使用:
List<Object> aList = new ArrayList<>();
这在定义类级别变量时很重要,因为即使您稍后更改了不重要的细节,也希望整个对象都能正常工作。
答案 7 :(得分:0)
看看这个问题: -
Polymorphism in java: Why do we set parent reference to child object?
在下面的方法中(工厂模式): -
public Animal doSomething(String str){
if(str.equals("dog")){
return new Dog();
}
else if(str.equals("cat")){
return new Cat();
}
else {
return new Animal();
}
}
你得到一种动物和Dog或Cat的实际对象,所以调用Animal的方法会调用在Dog或Cat的实际Object中重写的方法,如果被调用的方法在基类中被覆盖的话。它为您提供运行时的灵活性,以决定运行哪种方法,具体取决于实际对象和基类中的重写方法(如果有)。
完整示例如下: -
package com.test.factory;
public class Animal{
public void shout(){
System.out.println("Parent animal's shout");
}
}
package com.test.factory;
public class Dog extends Animal{
@Override
public void shout(){
System.out.println("bark..");
}
}
package com.test.factory;
public class Horse extends Animal{
@Override
public void shout(){
System.out.println("neigh");
}
}
package com.test.factory;
public class Lion extends Animal{
@Override
public void shout(){
System.out.println("roar..");
}
}
package com.test.factory;
public class AnimalFactory {
public Animal createAnimal(String str){
if(str.equals("dog")){
return new Dog();
}
else if (str.equals("horse")){
return new Horse();
}
else if(str.equals("lion")){
return new Lion();
}
else{
return new Animal();
}
}
}
package com.test.factory;
package com.test.factory;
public class Polymorphism {
public static void main(String[] args){
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.createAnimal("dog");
animal.shout();
animal = factory.createAnimal("lion");
animal.shout();
animal = factory.createAnimal("horse");
animal.shout();
animal = factory.createAnimal("Animal");
animal.shout();
}
}
Output is :-
bark..
roar..
neigh
Parent animal's shout
AnimalFactory有一个返回Animal的createAnimal方法。因为狗,狮子和马都是动物。因此,我们可以使用Animal返回类型创建Dog,Lion和Horse对象。我们使用Animal返回类型实现的是
Animal animal = new Dog();
Animal animal = new Lion();
Animal animal = new Horse();
没有Animal返回类型是不可能的。
如果我在createAnimal方法中使用返回类型作为Dog,那么它就不能返回Lion或Horse并且明智。