Учусь программировать. У меня есть классы (Базовый и производный). Когда в тестере вызываю метод 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)?
Потому, что так и задумано.
В абсолютном большинстве случаев программисту нужно именно чтобы вызывался метод производного класса. А приведение типа к базовому - лишь способ поместить объекты разных классов в один контейнер.
Продвижение своими сайтами как стратегия роста и независимости