Страницы

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

воскресенье, 8 декабря 2019 г.

Создание объекта класса в Java

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


начал разбираться с полиморфизмом и нашел следующий пример:
есть класс Soldier, и General - его наследник. У первого есть метод getHealth(),
у второго - getSlogan().

Не понятен принцип создания объекта класса.
Есть следующие строчки кода:

Soldier warrior1 = new Soldier();
General warrior2 = new Soldier();
Soldier warrior3 = new General();


Как происходит создание объекта. В первой строчке ми создаем объект типа солдат,
правильно? Тогда во второй выбьет ошибку, а третья создаст солдата и приведет к генералу?
Почему так и когда надо подобное приведение ведь проще сразу создать генерала типа генерал.

И второй вопрос ориентируясь по третей строчке я не могу применить warrior3.getSlogan(),только
warrior3.getHealth() ? А если бы метод getSlogan() был в солдате, то такой вызов был
бы возможен? И это благодаря полиморфизму?
    


Ответы

Ответ 1



Давайте начнем с понятия полиморфизм. Полиформизм - это такой свойство в данном случае метода, когда один и тот же метод ведет себя по разному. Возмем пример из жизни. Есть класс Животное. Есть класс Утка, которая насаледутся от Животное. Есть еще один класс Собака, которое тоже наследуется от Животное. Животное это абстракция, где мы можем просто определить метод Голос(). Мы его объявим абстрактным или виртуальным. Зависит от языка. Живтоных много, и каждый класс Утка и Собака будут иметь свои реализации для метода Голос(). Теперь когда мы можем создать Утку и Собаку и привести их к Живтоному. Псевдо код будет выглятеть так: Живтоное animals[2]; animals[0] = new Утка(); animals[1] = new Собака(); for (animal in animals) { animal.Голос(); } Т.е. при вызове метода Голос() мы не знаем реально, с каким объектом мы имеем дело, но можем вызвать именно его реализацию. В этом вся сила полиморфизма. Теперь ко вопросу про доступные методы. Тип переменной animal определяет доступные методы. Именно поэтому ни один метод из класса Утки не известен классу Животное. Приведение типов. Это отдельная большая тема. У нас есть возможно приводить типы двигаясь вверх или вниз по дереву наследования. Замечу, что двигаться вниз безопаснее в силу того, что мы знаем текущий тип объекта и можем точно знать от кого он наследуюется. Движение же верх (от абстракции к конкретике) более опасно и именно тут лучше использовать явное приведение типа, что бы подсказать компилятору. Все конечно зависит от языка. В вашем случае приведение к типу генерал невозможно т.к. объекта генерал в принцепе не существует. Есть только объект типа Солдат. Я очень рекомендую для начала разобраться в понятиях объект и тип. Тогда многое в ООП станет более понятным.

Ответ 2



Первая строчка создаст экземпляр Soldier и присвоит его переменной warrior1 Вторая строчка даже не скомпилируется, т.к. создается объект типа Soldier, а присваивается переменной warrior2 более специализированного типа General. Третья строчка создаст экземпляр General и присвоит его переменной warrior3 типа Soldier. Все нормально, генерал является солдатом в данной модели. Почему так и когда надо подобное приведение? Непосредственно в данном примере это приведение особого смысла не имеет. Оно лишь демонстрирует, что такое приведение возможно. В более общей картине мира, у вас может быть где-то еще метод kill(Soldier soldier), и, благодаря наследованию, вы сможете передавать в него и солдат и генералов. Внутри же методу kill на аргументе soldier будут доступны только те методы, которые объявлены в классе Soldier. Говорят, что метод kill абстрагируется от деталей реализации конкретного солдата. я не могу применить warrior3.getSlogan(), только warrior3.getHealth()? А если бы метод getSlogan() был в солдате, то такой вызов был бы возможен? И это благодаря полиморфизму? Все верно. И да, если бы в классе Soldier был аналогичный метод getSlogan(), то был бы возможен вызов warrior.getSlogan(). Причем, благодаря полиморфизму, был бы вызван именно генеральский getSlogan().

Ответ 3



Полиморфизм позволяет обращаться с объектом наследника так как будто это объект класса родителя. public class A { private int var = 1; int getVar() { return this.var; } } public class B extends A { } и где-то в коде: A a = new B(); a.getVar(); И это будет работать. НО! на оборот нельзя: B a = new A(); сразу ошибку выдаст так работать не будет! То есть указатель от более высокого по генеалогии класса может служить указателем для всех его наследников.

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

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