Учусь программировать. У меня есть классы (Базовый и производный). Когда в тестере вызываю метод draw(), то почему то отрабатывает как "PensilWithPen DRAW". Хотя я же привел к типу "Pen", и метод должен выполнятся из его тела?
Как мне сделать так, чтобы у объекта value вызвать метод draw() и чтобы он выполнил "PEN DRAW"
public class FirstClassTester {
public static void main(String[] args) {
Box<Pen> box = new Box();
box.set(new PensilWithPen());
Pen value = box.get();
value.draw();
}
}
class Pen{
public void draw(){
System.out.println("PEN DRAW");
}
}
class PensilWithPen extends Pen{
public void draw(){
System.out.println("PensilWithPen DRAW");
}
}
Это называется полиморфизм.
В Java если метод переопределен, то при вызове выполняется реализация метода, соответствующая реальному (PensilWithPen
) типу объекта, а не объявленному (Pen
) типу переменной. Методы с такой механикой вызова называются виртуальными. В Java все методы виртуальны.
Виртуальные методы позволяют обращаться к разным реализациям используя метод, определенный в родителе. Например:
//получаем pen, сгенерированный в другом классе
Pen pen = (new PenGenerator()).createPen();
//ручка рисует
pen.draw();
Так мы можем в любой момент заменить ручку в генераторе ручек (PenGenerator
). При этом вызывающий код не нужно будет переписывать.
Еще пример:
Pen[] pens = new Pen[]{pen, penWithPencil};
for(Pen pen : pens) {
//каждая ручка рисует по-своему, но метод всегда вызывается одинаково
pen.draw();
}
Та же логика применяется к методам интерфейсов. Поэтому к ним можно обратиться через интерфейс:
interface Pen {
void draw();
}
class PensilWithPen implements Pen{
public void draw(){
System.out.println("PensilWithPen DRAW");
}
}
...
Pen pen = new PensilWithPen();
//ручка рисует, хотя в самом Pen нет реализации
pen.draw();
Почитайте: Как на практике применяется полиморфизм?
В том виде, в котором Вы реализовали два класса — никак.
Если нужно вызывать от объекта класса-наследника обе реализации, то потребуется определить два метода.
Либо не переопределять метод вообще, а добавить новый:
class PensilWithPen extends Pen{
public void drawWithPencil(){
System.out.println("PensilWithPen DRAW");
}
}
...
PensilWithPen pensilWithPen = new PensilWithPen();
Pen pen = pensilWithPen;
//рисуем
pen.draw();
//рисуем по-новому
pensilWithPen.drawWithPencil();
Либо переопределить метод, но оставить вариант для вызова старого метода:
class PensilWithPen extends Pen{
public void draw(){
System.out.println("PensilWithPen DRAW");
}
public void drawPen(){
super.draw();
}
}
...
PensilWithPen pensilWithPen = new PensilWithPen();
Pen pen = pensilWithPen;
//рисуем по-новому
pen.draw();
//рисуем по-старому
pensilWithPen.drawPen();
Смотрите еще: Можно ли вызвать метод класса-родителя после его переопределения (Java)?
Потому, что так и задумано.
В абсолютном большинстве случаев программисту нужно именно чтобы вызывался метод производного класса. А приведение типа к базовому - лишь способ поместить объекты разных классов в один контейнер.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Насколько известно, изменив volatile переменную, мы остаёмся уверенны, что остальные потоки, которые будут её читать, получат новое значениеПричина...
файл сохраняется но он пустойпри дебаге выяснилось что output пустой
Пишу проекты на ReactПериодически требуется рендерить для ботов SPA на сервере