0
class Test {
    public static void main(String[] args) {
        Animal a = new Dog();
        Dog d = new Dog();

        d.makeNoise();  // output "Sub"
        a.makeNoise();  // output "Sub"  then what is use of calling this. why not call d.makeNoise() only.

    }
}

abstract class Animal {
    public void makeNoise() {
        System.out.println("Super");
    }
}

class Dog extends Animal {
    @Override
    public void makeNoise() {
        System.out.println("Sub");
    }
}

我们就这个话题进行了 15 分钟的讨论(我想 15 分钟太长了)我向面试官解释了如何a.makeNoise();
a.makeNoise();输出“Sub”然后调用它有什么用。为什么不只调用 d.makeNoise()
我也去了接口,但仍然有问题是子类引用是否给出相同的输出,那么为什么要使用超类引用。

面试官的问题是,有什么区别a.makeNoise();?为什么d.makeNoise();不只在两者都提供相同的输出时才调用?

可能的正确答案是什么?

4

8 回答 8

2

下面的示例说明了动态多态性。a 和 d 都被声明为 Animals,但 d 实际上是一只狗。

请注意,当我在 Animal d 上调用 makeNoise 时,java 会知道 d 实际上是一只狗,而不仅仅是任何动物。

class Test {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal d = new Dog();

        d.makeNoise();  // output "Bark"  - d is an animal that barks
        a.makeNoise();  // output "Squawk"  - a is an animal that squawks

    }
}

class Animal {
    public void makeNoise() {
        System.out.println("Squawk");
    }
}

class Dog extends Animal {
    @Override
    public void makeNoise() {
        System.out.println("Bark");
    }
}
于 2013-04-03T07:39:04.690 回答
2
Animal a = new Dog();    // this animal is a dog
Dog d = new Dog();       // this dog is a dog

狗就是狗,不管你怎么宣布它。

a.getClass()等于d.getClass()等于Dog.class

另一方面:

Animal a = new Animal(); // this animal is an animal
a.makeNoise();           // prints "Super"
于 2013-04-03T07:39:37.240 回答
1

这就是原因——

Animal a = new Dog();

动物是狗,所以噪音是一样的:)

如果使用该方法创建另一种动物,例如 Cat,并将动物指向 Cat,您应该会得到不同的噪音。

于 2013-04-03T07:35:43.427 回答
1

您的简化示例不能很好地展示这个案例。

Collection<Animal> caged = getCagedAnimals();
for (Animal a : caged)
  a.makeNoise();

由于有许多类型的动物(类),每一种都会发出不同的声音。可以这么说,我们不需要任何类型转换来获得不同的行为。想象一下,如果我们希望每只动物在没有多态性的情况下发出声音,将会发生什么可怕的事情:

for (Animal a : caged) {
  if (a instanceof Dog)
    ((Dog)a).woof(); // or, ((Dog)a).makeNoise()
  else if (a instanceof Cat)
    ((Cat)a).meow(); // or, ((Cat)a).makeNoise()
  else {...}
}

让我们有一个类型为 T 的对象。我们试图调用 toString()(由 Object 类定义) 动态方法调用过程如下(实际上是使用虚拟方法表):

C = T
do
  if (C defines toString()) {
    call T.toString()
    break
  }
  C = superclass of C
while (C != null)
throw new NoSuchMethodError();

现在,如果我们有

Object obj = new T();

我们打电话给

obj.toString();

我们实际上是在调用 T 类的 toString()。

于 2013-04-03T07:45:43.270 回答
1

考虑有3个类

  1. 动物
  2. 猫猫和狗是动物的子类。

class Test {
    public static void main(String[] args) {
        Animal a = new Animal();
       
    int user_input=userinput();  //returns 1 for cat and 2for dog
    switch(user_input)
    {
    case 1:Animal d=new Cat();
    break;
    case 2: Animal d=new Dog();
    break;
    }
        d.makeNoise();  // output "Bark"/"meow"  as per user input(dynamic linking)
        a.makeNoise();  // output "Squawk"  - a is an animal that squawks
    }
    } 
    class Animal {
    public void makeNoise() {
        System.out.println("Squawk");
    }
    } 
    class Cat extends Animal {
    @Override
    public void makeNoise() {
        System.out.println("meow");
    }
    }
    class Dog extends Animal {
    @Override
    public void makeNoise() {
        System.out.println("Bark");
    }
    }

于 2016-12-25T19:54:49.857 回答
0
class Account {
    public static void main(String[] args) {
        Animal a = new Dog();
        Dog d = new Dog();
        d.makeNoise();
        a.makeNoise();
        a = new Cat();
        a.makeNoise();
    }
}

abstract class Animal {
    public void makeNoise() {
        System.out.println("Super");
    }
}

class Dog extends Animal {
    public void makeNoise() {
        System.out.println("Sub");
    }
}

class Cat extends Animal {

}

参见上面的修改示例和观察结果

  1. 我们有一个抽象类 Animal,它有一个 makeNoise 的实现(这里我说默认实现)
  2. 我们有一个 Dog 类,它是 Animal 类型,但有一个自定义的 makeNoise 方法
  3. 我们有一个 Cat 类,它属于动物类型,但没有自定义的 makeNoise 方法。它使用 Animal 类型的默认 makeNoise。
  4. 如果我使用 Animal a = new Dog() 和 a.makeNoise(),那么我可以随时从 Dog 类中删除我的 makenoise 方法,而无需更改任何其他类。它仍然会编译和执行而不会出现任何错误。
  5. 如果我使用 Dog d = new Dog() 和 d.makeNoise(),那么我无法随时从 Dog 类中删除我的 makenoise 方法。如果这样做,我还需要更改要编译的应用程序的主类。
于 2013-04-03T08:42:56.020 回答
0

我会给一个普通的前任:-personA 有一个银行账户,他拥有该账户的所有权限(提款、存款、贷款等)。personB 想在这个时候将钱存入 personA 的账户,他想访问 personA 的账户,但我们只需要提供存款权限。

 class perosnB
{
 public void deposit()
{ 
................
 } 
 } 
class personA extends personB
{  
public void deposit()
{
......
}
public void withdraw() 
{ 
...... 
} 
} 
personA p=new personB(); 
PersonB p2=new personB(); 

通过使用 p 对象,我们只能访问withdraw 方法。通过使用p2,我们也可以访问存款。天气人A类是否抽象。如果 personA 是抽象类,则不可能为 personA 类创建对象( personA p=new personA()) 。personA p=new personB() 是可能的。

于 2013-04-03T09:23:02.013 回答
0
Animal a = new Dog();

a 是Animal类型的引用,但它引用Dog类型的对象。

这里Dog覆盖了Animal类的makeNoise()方法。

class Animal {
    public void makeNoise() {
        System.out.println("Squawk");
    }
}

class Dog extends Animal {
    @Override
    public void makeNoise() {
        System.out.println("Bark");
    }
}

由于对象属于Dog类,JVM 会将Dog类的makeNoise()方法绑定到对象,并且绑定将在运行时完成。

所以输出

a.makeNoise();

将会

于 2014-05-19T17:33:46.427 回答