Страницы

Поиск по вопросам

суббота, 28 декабря 2019 г.

Особенности полиморфизма

#java #jvm #полиморфизм


Всем доброго времени суток.

Только начал готовиться к собеседованию на Java Junior`а, как произошло небольшое
недопонимание по поводу полиморфизма. Я изучал Java Core по книге Кэти Сьерра и Берта
Бейтса("Изучаем Java. 2-е издание"). 

Там механизм наследования (и вообще хранения объектов в куче JVM) представлялся вот так:

public class A{
//code...
}

public class B extends A{
//code...
}

public class TestApp{

public void init(){
B val = new B();
}

}


И в JVM это все выглядит таким образом:



Допустим, у нас есть такой код:

public class Animal{

public void makeSomthing(){
System.out.println("Animal"); 
} 

}


public class Dog extends Animal{

//переопределенный метод
@Override
public void makeSomthing(){
System.out.println("Dog");
} 

public void fMagic(){

this.makeSomthing(); //Console: Dog    
super.makeSomthing(); //Console: Animal [?]   

}

}


public class TestApp{

public static void main(String[] args){

Dog dogPet = new Dog();

dogPet.fMagic();

}

}


Выходит, что при вызове метода fMagic() у объекта dogPet так же вызывается метод
makeSomthing() у "внешнего" объекта Dog и еще этот же метод вызывается у "внутреннего"
объекта Animal(у суперкласса). Как я понял, по логике этой книги, конструкция переопределения(@Override)
методов заключается в том, что метод по сути один, а когда мы его переопределяем, то
как-бы изменяем его во "внутреннем" объекте c помощью "внешнего". А уже при вызове
dogPet.fMagic() он вызывается изнутри.



Но при этом:

класс Dog

   public void fMagic(){

    this.makeSomthing(); //Console: Dog
    super.makeSomthing(); //Console: Animal [?]

    //Console:  Dog@74a14482 -  адрес Dog. Dog@74a14482 - адрес Animal. 
    System.out.println("links:"+"\n" + this + " -  адрес Dog. "+ super.getObjectLink()
+ " - адрес Animal.");

}


класс Animal

 public Object getObjectLink(){ return this; }


Но самое странное на мой взгляд заключается вот в этом:
При сужении типа до его родителя, вызов функции дает "Dog", а не "Animal". Т.е в
данном случае, переопределение метода в классе Dog изменяет метод saySomthing(). А
вот в случае вызова метода fMagic() у класса Dog, вызываются 2 разные функции И переопределение
функции суперкласса, как я понимаю, ничего не дает. 

 Animal dogPet = new Dog();

 dogPet.makeSomthing(); //Console: Dog


Суть вопроса: Как же именно все эти процессы и механизмы ООП происходят на самом
деле? И почему же при вызове fMagic() на консоль выводится две разные надписи "Dog"
и "Animal", а не одна и та же надпись "Dog", как в случае с Animal dogPet = new Dog();?
    


Ответы

Ответ 1



Во-первых завязывайте с такой терминологией, нет никаких внешних и внутренних объектов. У вас есть класс Dog, который расширяет класс Animal. Наследование представляет собой отношение типа является(is a). Следовательно в Вашем случае объект Dog является объектом Animal, а значит содержит в себе его поведение. Поведение родительского класса может использоваться в подклассе при помощи ключевого слова super, что Вы и продемонстрировали. Ключевое слово this используется для получения объектом ссылки на самого себя, что в данном случае делается по-умолчанию. Т.е. Вы получите такой же результат если опустите его. Чтобы лучше понять преимущества полиморфизма разберите паттерн проектирования "Стратегия". На мой взгляд один из самых ярких примеров. Также если Вы пишете Animal dog = new Dog(); Вы говорите машине: "Создай мне объект Dog и помести его в переменную типа Animal". Вы можете это сделать, поскольку Dog является Animal. Однако обращаясь к этой переменной у Вас будет вызываться метод класса Dog поскольку в ней содержится объект Dog. Animal здесь - это тип переменной, а не объекта.

Комментариев нет:

Отправить комментарий