прехвърляне на обект от подклас като суперклас

Имам някакъв въпрос относно upcast/downcast.

Създадох абстрактен супер клас Animal, подклас Dog и подклас BigDog. и аз също давам абстрактен метод в Animal и го замествам в Dog и BigDog.

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. Въпросът ми обаче е, можете ли да прехвърлите суперклас в конкретен подклас, знаейки, че има клас между тях? например, ако имам обект от клас Animal, който съдържа обект BigDog, мога ли да прехвърля обекта към Dog? какво ще стане, ако има методи в BigDog, които не съществуват в Dog?

накратко, със сигурност можете да кажете, че обект от суперклас е обект от подклас, но защо можете да инвертирате?


Като се замисля,

Предполагам това: питам JVM да прехвърли препратка към клас Animal към Dog и да свърже новата препратка Dog към обекта BigDog, вместо наистина да предаде обекта BigDog.

Така че мога да извикам всички методи Dog и Animal върху тази препратка Dog (към BigDog), но нито един от методите BigDog, освен ако не е бил заменен в BigDog.

Това, което Java проверява при извикване на метод, е: дали препратката (DOG) има препратката и дали обектът (BigDog) има отмяна. ако не, се извиква метод Dog, в противен случай се извиква метод BigDog.

Може ли някой да потвърди предположението ми?


person sygede    schedule 30.08.2013    source източник
comment
Правилното използване на методите: dog2.greeting(); и dog3.greeting(); или добавете метод public void greeting(Animal animal);. След това изходният код ще се компилира.   -  person Pawel    schedule 30.08.2013
comment
съжалявам, момчета, копирайте и поставете, забравихте да промените параметрите.   -  person sygede    schedule 31.08.2013
comment
Това е добър пример за статичен срещу динамичен тип променлива. Има няколко книги/теми за това   -  person Stefan Warminski    schedule 21.03.2018


Отговори (4)


Винаги можете да преобразувате към определен подклас, освен ако компилаторът не е достатъчно умен, за да знае със сигурност, че преобразуването ви е невъзможно.

Най-добрият начин за прехвърляне към подклас е да проверите дали може да се направи:

  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 на променлива Animal, а се запази като Dog.

person extraneon    schedule 30.08.2013

If I have an Animal class object contains a BigDog object, can I cast the object to Dog? what if there are methods in BigDog that do not exist in Dog?.

Просто ще получите грешка на компилатора. Тъй като не можете да извикате метод, който не е деклариран в родител и деклариран в дъщерен клас, използвайки препратка към родител

person Prabhaker A    schedule 30.08.2013

Няма метод, чийто подпис да съответства на тези извиквания на метод:

dog2.greeting(dog3);
dog3.greeting(dog2); 

така че това е почти неуспешна компилация.

Трябва да знаете за динамичния метод за изпращане.

ето няколко връзки 1,2,3 преминете през тях.

person codeMan    schedule 30.08.2013
comment
моя грешка при копиране и поставяне. оригиналният код има методи. - person sygede; 31.08.2013
comment
Добре. Преминете през връзките, които са там в отговора. Greeting() на който ще бъде извикан обектът, към който препратката към кучето се отнася. - person codeMan; 02.09.2013

Първо коригирайте изходния код, за да се компилира. Правилното използване на методите: dog2.greeting(); и dog3.greeting(); или добавете метод public void greeting(Animal animal);.


dog3.greeting(); - извикване на метод greeting() за dog3. dog3 има същата препратка като animal3. animal3 има препратка към BigDog, така че метод greeting() се извиква към класа BigDog и изходът е Woow!


Когато наследите Dog от клас Animal, тогава клас Dog има всички методи от клас Animal.

person Pawel    schedule 30.08.2013