#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 здесь - это тип переменной, а не объекта.
Комментариев нет:
Отправить комментарий