Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Документ Microsoft Word.docx
Скачиваний:
7
Добавлен:
15.05.2015
Размер:
201.46 Кб
Скачать

Полиморфизм.

В более общем смысле, концепцией полиморфизма является идея «один интерфейс, множество методов«.

Это означает, что можно создать общий интерфейс для группы близких по смыслу действий. Преимуществом полиморфизма является то, что он помогает снижать сложность программ, разрешая использование того же интерфейса для задания единого класса действий. Выбор же конкретного действия, в зависимости от ситуации, возлагается на компилятор.

Вам, как программисту, не нужно делать этот выбор самому. Нужно только помнить и использовать общий интерфейс.

?

1

2

3

4

5

6

7

public class Parent {

    int a = 2;

}

 

public class Child extends Parent {

    int a = 3;

}

Прежде всего, нужно сказать, что такое объявление корректно.

Наследники могут объявлять поля с любыми именами, даже совпадающими с родительскими. Объекты класса Child будут содержать сразу две переменных, а поскольку они могут отличаться не только значением, но и типом (ведь это два независимых поля), именно компилятор будет определять, какое из значений использовать.

Компилятор может опираться только на тип ссылки, с помощью которой происходит обращение к полю:

?

1

2

3

4

Child c = new Child();

System.out.println(c.a); // результатом будет 3

Parent p = c;

System.out.println(p.a); //результатом будет 2

Обе ссылки указывают на один и тот же объект, но тип у них разный. Отсюда и результат. Объявление поля в классе-наследнике «скрыло» родительское поле.

Данное объявление так и называется – «скрывающим». Родительское поле продолжает существовать.

К нему можно обратиться явно:

?

1

2

3

4

5

class Child extends Parent {

     int a = 3;                     //скрывающее объявление

     int b = ((Parent)this).a;      //громоздкое обращение к родительскому полю

     int c = super.a;               //простое обращение к родительскому полю

}

Переменные b и получат значения, родительского поля a. Хотя выражение с super более простое, оно не позволит обратиться на два уровня вверх по дереву наследования.

А ведь вполне возможно, что в родительском классе это поле также было скрывающим и в родителе родителя храниться еще одно значение.

К нему можно обратиться явным приведением, как это делается для b.

?

1

2

3

4

5

6

7

8

9

10

class Parent {

     int x = 0;

     public void printX() {

          System.out.println(x);

     }

}

 

class Child extends Parent {

     int x = -1;

}

Каков будет результат для new Child.printX(); ?

Метод вызывается с помощью ссылки типа Child, но метод определен в классеParent и компилятор расценивает обращение к полю в этом методе именно как к полю класса Parent. Результатом будет 0.

 

Рассмотрим случай переопределения методов:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

class Parent {

     public int getValue() {

          return 0;

     }

}

 

class Child extends Parent {

     public int getValue() {

          return 1;

     }

}

 

Child c = new Child();

System.out.println(c.getValue()); // результатом будет 1

Parent p = c;

System.out.println(p.getValue()); // результатом будет 1

Родительский метод полностью перекрыт.

В этом ключевая особенность полиморфизма – наследники могут изменить родительское поведение, даже если обращение к ним производиться по ссылке родительского типа.

Хотя старый метод снаружи недоступен, внутри класса-наследника к нему можно обратиться с помощью super.

Статические методы, подобно статическим полям принадлежат классу и появление наследников на них не сказывается. Статические методы не могут перекрывать обычные методы и наоборот.