Переопределение методов
В случае, если метод в подклассе имеет такое же имя, тип и список параметров, как метод в его суперклассе, то метод в подклассе переопределяет (override) метод в суперклассе. Когда переопределенный метод вызывается в подклассе, он будет всегда обращаться к версии этого метода, определенной подклассом. Версия метода, определенная суперклассом, будет скрыта.
Рассмотрим следующий фрагмент (проект Override файл Override.java):
// Переопределение методов.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// показать i и j на экране
void show() {
System.out.println("i и j: " + i + " " + j);
}
}
class В extends A {
int k;
В(int a, int b, int c) {
super(a, b);
k = c;
}
// Показать на экране k (этот show() переопределяет show() из A)
void show() {
System.out.println("k: " + k);
}
}
class Override {
public static void main(String args[]) {
В subOb = new В(1, 2, 3);
subOb.show(); // здесь вызывается show() из В
}
}
Переопределение метода происходит только тогда, когда имена, возвращаемые значения и параметры этих двух методов идентичны. Если это не так, то оба метода просто перегружены. Например, рассмотрим следующую модифицированную версию предыдущего примера (проект Override файл Override2.java):
// Методы с различными сигнатурами типов перегружаются,
// а не переопределяются.
class A {
int i, j;
A(int a, int b) {
i = a;
j = b;
}
// Показать i и j
void show() {
System.out.println("i и j: " + i + " " + j) ;
}
}
// Создать подкласс В расширением класса А.
class B extends A {
int k;
B(int a, int b, int c) {
super(a, b);
k = c;
}
// Перегруженный show()
void show(String msg) {
System.out.println(msg + k) ;
}
}
class Override2 {
public static void main(String args[]) {
B subOb = new B(1, 2, 3);
subOb.show("Это к: "); // вызов show() класса В
subOb.show(); // вызов show() класса A
}
}
Полиморфизм времени выполнения
Полиморфизм времени выполнения это механизм, с помощью которого решение на вызов переопределенной функции принимается во время выполнения, а не во время компиляции.
Поскольку ссылочная переменная суперкласса может обращаться к объекту подкласса, Java может принимать решения о вызове переопределенных методов во время выполнения. Когда переопределенный метод вызывается через ссылку суперкласса, Java определяет, какую версию этого метода следует выполнять, основываясь на типе объекта, на который указывает ссылка в момент вызова. Когда ссылка указывает на различные типы объектов, будут вызываться различные версии переопределенного метода. Именно тип объекта, на который сделана ссылка (а не тип ссылочной переменной) определяет, какая версия переопределенного метода будет выполнена.
Например (проект Dispatch файл Dispatch.java):
// Динамическая диспетчеризация методов.
class A {
void callme () {
System.out.println("Внутри А метод callme");
}
}
class B extends A {
// переопределить callme()
void callme() {
System.out.println("Внутри В метод callme");
}
}
class C extends A {
// переопределить callme()
void callme() {
System.out.println("Внутри С метод callme");
}
}
class Dispatch {
public static void main(String args[]) {
A a = new A(); // объект типа A
B b = new B(); // объект типа В
C с = new C(); // объект типа С
A r; // определить ссылку типа А
r = a; // r на А-объект
r.callme(); // вызывает А-версию callme
r = b; // r указывает на В-объект
r.callme(); // вызывает В-версию callme
r = с; // r указывает,на С-объект
r.callme(); // вызывает С-версию callme
}
}
Еще один пример (проект FindAreas файл FindAreas.java):
