
5. Наследование
Наследование является неотъемлемой частью любого ООП языка. Даже если класс не является производным от другого класса, он автоматически наследует корневому классу Java.Object.
В нотации UML наследование выглядит так:
Синтаксис:
<модификатор доступа> class имя_подкласса extends имя_суперкласса {
Тело класса…
}
Подкласс (наследник, дочерний класс) наследует поля и методы, включая конструктор, базового класса (суперкласса), если они не определены c модификатором доступа private, а также может иметь свои поля и методы.
Пример:
public class Shape { //фигура
public double area, perimeter; //площадь, периметр
public Shape() { //конструктор
this.area = 0;
this.perimeter = 0;
}
public double areaCalc() {
return 0;
}
public double perimeterCalc() {
return 0;
}
//вывод результата
public void shapeMethod() {
System.out.println("Площадь фигуры " + this.area);
System.out.println("Периметр фигуры " + this.perimeter);
System.out.println();//отступ
}
} // конец описания класса
// класс-наследник - окружность
public class Circle extends Shape{
public int radius;
public Circle(int r) { //конструктор
super();
this.radius = r;
}
public double areaCalc() {
double pi = 3.1415;
return pi*radius*radius;
}
public double perimeterCalc() {
double pi = 3.1415;
return 2*pi*radius;
}
public class Main {
public static void main(String[] args) {
Shape sh = new Shape ();
Circle cir = new Circle(5);
cir.area = cir.areaCalc();
cir.perimeter = cir.perimeterCalc();
sh.shapeMethod();
cir.shapeMethod();
}
}
Результаты работы:
Площадь фигуры 0.0
Периметр фигуры 0.0
Площадь фигуры 78.53750000000001
Периметр фигуры 31.415000000000003
Полиморфизм
Рассмотрим класс Shape наследник Circle из примера выше. Добавим ещё два дочерних класса Triangle (треугольник) и Square (квадрат).
Каждый из дочерних классов наследует поля родителя area и perimeter и его конструктор и переопределяет методы нахождения площади и периметра фигуры.
Полиморфизм основан на понятии «позднего связывания» и динамического вызова методов.
Раннее связывание «метод-вызов» происходит на этапе компиляции.
Позднее связывание – на этапе запуска.
// класс-наследник - треугольник
public class Triangle extends Shape{
public int a, b, c; //стороны треугольника
//конструктор
public Triangle (int aa, int bb, int cc) {
super();
this.a = aa;
this.b = bb;
this.c = cc;
}
public double areaCalc() {
double p = (a + b + c)/2.0;
return Math.sqrt(p(p - a)(p - b)(p - c));
}
public double perimeterCalc() {
return a + b + c; }
// класс-наследник - квадрат
public class Square extends Shape{
public int a; //стороны прямоугольника
public Square (int aa) { //конструктор
super();
this.a = aa;
}
public double areaCalc() {
return a*a;
}
public double perimeterCalc() {
return 4*a;
}
}
public static void main(String[] args) {
Shape[] sh = new Shape[4];
Shape sh0 = new Shape();
Circle sh1 = new Circle(3);
Triangle sh2 = new Triangle(2, 3, 4);
Square sh3 = new Square(3);
sh[0] = sh0;
sh[1] = sh1;
sh[2] = sh2;
sh[3] = sh2;
for (int i = 0; i <= 3; i++) {
sh[i].area = sh[i].areaCalc();
sh[i].perimeter = sh[i].perimeterCalc();
}
for (int i = 0; i <= 3; i++) sh[i].shapeMethod();
}
Методы areaCalc() и perimeterCalc() и их вызовы – пример полиморфизма
Объявления типа:
Shape sh2 = new Triangle(2, 3, 4);
Или
Shape sh3 = new Square(3);
называют «восходящим преобразованием».
Здесь Shape – класс-родитель, Triangle и Square – классы-потомки.
Можно было в методе main() задать так:
Shape[] sh = {new Shape(), new Circle(3), new Triangle(2, 3, 4), new Square(3)};
Результат работы:
Площадь фигуры 0.0
Периметр фигуры 0.0
Площадь фигуры 28.2735
Периметр фигуры 18.849
Площадь фигуры 2.9047375096555625
Периметр фигуры 9.0
Площадь фигуры 9.0
Периметр фигуры 12.0