Вход/Регистрация
Программирование на Java
вернуться

Вязовик Н.А.

Шрифт:

class Child extends Parent {

int a=3;

// скрывающее объявление

int b=((Parent)this).a;

// более громоздкое объявление

int c=super.a;

// более простое

}

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

Рассмотрим следующий пример:

class Parent {

int x=0;

public void printX {

System.out.println(x);

}

}

class Child extends Parent {

int x=-1;

}

Каков будет результат следующих строк?

new Child.printX;

Значение какого поля будет распечатано? Метод вызывается с помощью ссылки типа Child, но это не сыграет никакой роли. Вызывается метод, определенный в классе Parent, и компилятор, конечно, расценил обращение к полю x в этом методе именно как к полю класса Parent. Поэтому результатом будет 0.

Перейдем к статическим полям. На самом деле, для них проблем и конфликтов, связанных с полиморфизмом, не существует.

Рассмотрим пример:

class Parent {

static int a=2;

}

class Child extends Parent {

static int a=3;

}

Каков будет результат следующих строк?

Child c = new Child;

System.out.println(c.a);

Parent p = c;

System.out.println(p.a);

Нужно вспомнить, как компилятор обрабатывает обращения к статическим полям через ссылочные значения. Неважно, на какой объект указывает ссылка. Более того, она может быть даже равна null. Все определяется типом ссылки.

Поэтому рассматриваемый пример эквивалентен:

System.out.println(Child.a)

System.out.println(Parent.a)

А его результат сомнений уже не вызывает:

3

2

Можно привести следующее пояснение. Статическое поле принадлежит классу, а не объекту. В результате появление классов-наследников со скрывающими (hiding) объявлениями никак не сказывается на работе с исходным полем. Компилятор всегда может определить, через ссылку какого типа происходит обращение к нему.

Обратите внимание на следующий пример:

class Parent {

static int a;

}

class Child extends Parent {

}

Каков будет результат следующих строк?

Child.a=10;

Parent.a=5;

System.out.println(Child.a);

В этом примере поле a не было скрыто и передалось по наследству классу Child. Однако результат показывает, что это все же одно поле:

5

Несмотря на то, что к полю класса идут обращения через разные классы, переменная всего одна.

Итак, наследники могут объявлять поля с именами, совпадающими с родительскими полями. Такие объявления называют скрывающими. При этом объекты будут содержать оба значения, а компилятор будет каждый раз определять, с каким из них надо работать.

Методы

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

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);

Parent p = c;

System.out.println(p.getValue);

Результатом будет:

1

1

Можно видеть, что родительский метод полностью перекрыт, значение 0 никак нельзя получить через ссылку, указывающую на объект класса Child. В этом ключевая особенность полиморфизма – наследники могут изменять родительское поведение, даже если обращение к ним производится по ссылке родительского типа. Напомним, что, хотя старый метод снаружи уже недоступен, внутри класса-наследника к нему все же можно обратиться с помощью super.

Рассмотрим более сложный пример:

class Parent {

public int getValue {

return 0;

}

public void print {

System.out.println(getValue);

}

}

class Child extends Parent {

public int getValue {

return 1;

}

}

Что появится на консоли после выполнения следующих строк?

Parent p = new Child;

p.print;

С помощью ссылки типа Parent вызывается метод print, объявленный в классе Parent. Из этого метода делается обращение к getValue, которое в классе Parent возвращает 0. Но компилятор уже не может предсказать, к динамическому методу какого класса произойдет обращение во время работы программы. Это определяет виртуальная машина на основе объекта, на который указывает ссылка. И раз этот объект порожден от Child, то существует лишь один метод getValue.

  • Читать дальше
  • 1
  • ...
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: