Java 将子类对象强制转换为超类

Java 将子类对象强制转换为超类,java,class,casting,subclass,superclass,Java,Class,Casting,Subclass,Superclass,我有一些关于上抛/下抛的问题 我创建了一个抽象的超类动物,子类狗和子类大狗。我还给出了动物的抽象方法,并在狗和大狗中重写了它 abstract public class Animal { abstract public void greeting(); } public class Dog extends Animal { @Override public void greeting() { System.out.println("Woof!"); } }

我有一些关于上抛/下抛的问题

我创建了一个抽象的超类动物,子类狗和子类大狗。我还给出了动物的抽象方法,并在狗和大狗中重写了它

abstract public class Animal {
    abstract public void greeting();
}

public class Dog extends Animal {
   @Override
   public void greeting() {
      System.out.println("Woof!");
   }
}

public class BigDog extends Dog {
   @Override
   public void greeting() {
      System.out.println("Woow!");
   }
}
现在,我的测试代码:

public class TestAnimal {
   public static void main(String[] args) {

      Animal animal2 = new Dog();
      Animal animal3 = new BigDog();

      // Downcast
      Dog dog2 = (Dog) animal2;               //cast Animal class to Dog class, legit
      BigDog bigDog2 = (BigDog) animal3;      //cast Animal to BigDog, legit;
      Dog dog3 = (Dog) animal3;               //Animal Class contains BigDog cast into Dog?
      dog2.greeting();
      dog3.greeting();                    //in which class the method is called?
   }
}
我理解超类/子类之间的关系以及cast是如何工作的。然而,我的问题是,你能把一个超类转换成一个特定的子类吗?你知道中间有一个类吗?例如,如果我有一个动物类对象包含一个BigDog对象,我可以将该对象强制转换为Dog吗?如果BigDog中有一些方法在Dog中不存在呢

简而言之,可以肯定地说,超类对象是子类对象,但为什么可以反转呢


仔细想想

我猜是这样的:我要求JVM将动物类引用转换为Dog,并将新的Dog引用链接到BigDog对象,而不是真正转换BigDog对象

所以我可以调用该Dog引用(到BigDog)上的所有Dog和Animal方法,但是没有一个BigDog方法,除非它在BigDog中被重写

Java在调用方法时检查的是:引用(DOG)是否有引用,对象(BigDog)是否有重写。否则,将调用BigDog方法


有人能证实我的猜测吗?

没有签名与这些方法调用匹配的方法:

dog2.greeting(dog3);
dog3.greeting(dog2); 
因此,这几乎是一次编译失败

您需要了解动态方法调度


这里有几个链接,请浏览。

如果我有一个动物类对象包含一个BigDog对象,我可以将该对象强制转换为Dog吗?如果BigDog中存在Dog中不存在的方法怎么办?


您将得到编译器错误。因为您不能调用未在父类中声明且使用父引用在子类中声明的方法,请首先更正源代码,这样它将编译。方法的正确使用:
dog2.greeting()
dog3.greeting()或添加方法<代码>公共无效问候语(动物)


dog3.greeting()-调用
dog3
的方法
greeting()
dog3
animal3
具有相同的引用
animal3
引用了
BigDog
,因此方法
greeting()
被调用到类
BigDog
,输出为
Woow



当您从class
Animal
继承
Dog
时,则class
Dog
具有class
Animal
的所有方法,您始终可以强制转换到特定的子类,除非编译器足够聪明,能够确定您的强制转换是不可能的

强制转换到子类的最佳方法是检查是否可以执行:

  if ( doggy instanceof BigDog ) {
      doSomethingWithBigdog( (BigDog) doggy );
  } else if ( doggy instanceof SmallDog ) {
      doSomethingWithSmalldog( (SmallDog) doggy );     
  } else {
     // Neither a big dog nor a small dog
  }

  ...

  private void doSomethingWithBigdog( BigDog dog ) {
    ...
  }

  private void doSomethingWithSmalldog( SmallDog dog ) {
    ...
  }

记住铸造是邪恶的。有时是必要的,但通常(并非总是)可以通过在基类上实现方法来设计,或者不将Dog分配给动物变量,而是将其保留为Dog。

方法的正确用法:
dog2.greeting()
dog3.greeting()或添加方法<代码>公共无效问候语(动物)。然后源代码将被编译。很抱歉,复制和粘贴的人忘记了更改参数。这是静态和动态类型变量的一个很好的例子。有好几本书/几条线索说明了我在复制和粘贴时的错误。原始代码必须为methods.ok。浏览答案中的链接。将调用dog引用所引用的对象的问候语()。