Top.Mail.Ru

Перечень уроков по Java

19, Практика. Полиморфизм

Рассмотрим пример с геометрическими фигурами. Имеется базовый класс c именем Figura  и несколько производных классов: окружность (тип Circle), прямоугольник (тип Rect) и трапеция (тип Trap). Необходимо определить площадь каждой фигуры и вывести эти значения на печать.

Вот листинг классов.

public class Figura {

        public double Area (){

            return 0;

        }

        public void PrintArea(){}

}

Обратите внимание, класс не имеет явно записанного конструктора. Компилятор будет использовать конструктор по умолчанию.

Класс содержит два пустых метода Area() и PrintArea(), которые в данном классе совершенно ничего не делают, но их наличие крайне важно: именно через них будет в последующем обеспечен полиморфизм.

public class Circle extends Figura{

    int a;

     public  Circle (int A)

    {

        a=A;

    }

       

    public double Area (){

            return Math.PI*a*a;

    }

  

    public void PrintArea(){

    System.out.println("Площадь круга: "+ Area());

    }

}

Класс Circle является производным от класса Figura, на это указывает ключевое слово extends. Данный класс содержит конструктор public  Circle (int A), методы Area() и    PrintArea(), которые переопределены в Circle (имя метода как у родителя, а в внутри каждого метода записан другой программный код). 

Выполним создание объекта класса Circle, следующим образом:

   Figura f = new Circle(1);

Первое впечатление - это ошибка. Мы видим присвоение между переменными разного типа (тип Figura и тип Circle). Но это не так. Операция допустима, поскольку тип Circle (окружность) является типом Figura посредством наследования.

Все  ссылки на объекты производных классов совместимы по типу с ссылками на объекты базового класса.

 

Выполним метод Area ()

f.Area ();

Какой метод Area() будет вызван: из класса  Figura  или класса Circle?

При выполнении данного оператора работает механизм динамического или позднего связывания. На данном  этапе выполнения программы уже известно, что был создан объект типа Circle и ссылка на этот объект была присвоена переменной f. Следовательно, будет вызван метод Area() класса Circle. Так происходит автоматический выбор нужного метода для исполнения. 

Продолжим листинг классов.

//класс прямоугольник

public class Rect extends Figura {

     int a;

     int b;

    

    public  Rect (int A, int B)

    {

        a=A;

        b=B;

    }

    public double Area (){

               return a*b;

    }

   

    public void PrintArea(){

    System.out.println("Площадь прямоугольника: "+ Area());

    }

}

//класс трапеция

public class Trap extends Figura{

     int a;

     int b;

     int h;

    

    public  Trap (int A, int B, int H)

    {

        a=A;

        b=B;

        h=H;

    }

    public double Area (){

              return (a + b)*h/2;

    }

   

    public void PrintArea(){

    System.out.println("Площадь трапеции: "+ Area());

    }

 }

Метод  main()

   public static void main(String[] args) {

        //создаем массив ссылок на базовый класс

        Figura [] f = new Figura [5];

        //создаем объекты, ссылки на объеты храним

        //в массиве ссылок базового класса

         f[0]= new Circle(1);

         f[1]= new Rect(1,1);

         f[2]= new Trap(1,1,1);

         f[3]= new Circle(1);

         f[4]= new Rect(1,1);

        

         //работает механизм полимофизма

         for(int i=0; i<f.length; i++)

                 f[i].PrintArea();

    }

Результат работы:

Площадь круга: 3.141592653589793
Площадь прямоугольника: 1.0
Площадь трапеции: 1.0
Площадь круга: 3.141592653589793
Площадь прямоугольника: 1.0

Полиморфизм  проявляется строке

                 f[i].PrintArea();

где один и тот же метод используется для вычисления площади разных фигур (окрухность Circle, прямоугольник Rect и трапеция  Trap).