Объясните пожалуйста для чего это, если мы создали класс Animal, потом Cat extends Animal, для чего создают объекты вида Animal barsik = new Cat(); если могли просто Cat barsik = new Cat(); и это разновидность полиморфизма, или только override полиморфизм?
3 Answers
Напоминает диалог:
- Боб: у меня есть кот
- Алиса: О, у тебя есть животное?
- Боб: нет, у меня кот
- Алиса: ну он же кот - значит животное?
- Боб: эмм... это полиморфизм или абстракция?
- Бабушка: хватит уже, он Барсик и он член семьи!
Update
Надеялся, что поймете, но не судьба. Посему буду объяснять:
Судьба кота зависит от точки зрения (или если угодно от Use Case)
- Для Боба, который собирается его тискать и гладить - кот безусловно
Cat - Для Алисы, которая даже и не знала о его существовании - он еще один
Animal - Для бабушки - он не просто кот, а конкретно
barsik instanceof Cat
Соответственно, когда вы пишете Animal barsik=new Cat() - это означает, что вы собираетесь дальше юзать кота как животное, вам достаточен уровень абстракции Animal. Но, если дальше у вас в коде начинаются операции типа: (Cat )barsik - значит что-то пошло не так... - вам таки нужен был уровень абстракции Cat barsik=new Cat()
Дальше больше - дальше начинается философия: правильный прогер, всегда должен пользоваться максимальным уровнем абстракции (обратите внимание, что я лично не совсем соглашаюсь с такой философией). Некоторые особо упоротые интервьюеры спецом заваливают несчастного претендента на куске кода типа:
ArrayList<String> strings=new ArrayList<String>();
for(String s: strings)
System.out.println(s);
С вопросом - что в этом коде не так? Правильный ответ:
List<String> strings=new ArrayList<String>();
for(String s: strings)
System.out.println(s);
Для переменной strings уровень ArrayList<> излишен, достаточно только интерфейса List
- 81,300
-
Вроде я не совсем бред написал, имею ввиду виртуальные методы, но не понимаю зачем и хотелось простой ответ на мой вопрос! – blomo Dec 12 '19 at 11:12
-
Ответ явно не содержит информацию, разъясняющую причины использования абстракций, вместо конкретных типов. – nikialeksey Dec 12 '19 at 11:37
-
см. апдейт ответа – Barmaley Dec 13 '19 at 06:51
Если мы работает с этими объектами на уровне интерфейса, определённого в абстрактном классе Animal, то лучше объявлять соответствующую переменную или поле как Animal, чтобы не быть зависимым от конкретной её реализации, которую можно будет легко изменить в одном месте, не меняя весь остальной код, использующий Animal. Это и есть преимущество полиморфизма. Если же нам нужно вызывать какие-то методы, которые есть только у Cat, то нет другого выхода кроме как объявлять соответствующие переменные и поля конкретным классом Cat или же ввести ещё один абстрактный класс Feline (род кошачьих в биологии), с дополнительными методами, от которого Cat и будет наследовать. Таким образом цепочка наследования будет такой Animal -> Feline -> Cat.
- 2,183
Если очень простым языком, то можно работать с котами класса Cat - заполнить ими массив (ArrayList), производить над ними свойственные котам действия (кормить, поить, вычесывать, водить к ветеринару).
В какой-то момент в вашем кошачьем царстве появляется, например, пара собак класса Dog. Можно, конечно, создать для них отдельный массив ArrayList и никогда не смешивать котов и собак.
Но есть и другой вариант - выделить общие черты кошек и собак в отдельный класс животного (Animal - кличка, возраст, метод покормить), от которого наследовать классы Cat и Dog (чтобы кличка, возраст и покормить были у обоих видов). А когда потребуется покормить всех животных, можно создать массив с классом их родителя ArrayList, в который прекрасно запишутся как кошки (new Cat()), так и собаки (new Dog()), у которых можно будет вызывать общие методы, не задумываясь кого ты конкретно кормишь.
Ответ на вопрос о том, наследование или полиморфизм - тут речь про наследование.