Вязовик Н.А.
Шрифт:
Проверка уровня доступа проводится компилятором. Обратите внимание на следующие примеры:
public class Wheel {
private double radius;
public double getRadius {
return radius;
}
}
Значение поля radius недоступно снаружи класса, однако открытый метод getRadius корректно возвращает его.
Рассмотрим следующие два модуля компиляции:
package first;
// Некоторый класс Parent
public class Parent {
}
package first;
// Класс Child наследуется от класса Parent,
// но имеет ограничение доступа по умолчанию
class Child extends Parent {
}
public class Provider {
public Parent getValue {
return new Child;
}
}
К методу getValue класса Provider можно обратиться и из другого пакета, не только из пакета first, поскольку метод объявлен как public. Данный метод возвращает экземпляр класса Child, который недоступен из других пакетов. Однако следующий вызов является корректным:
package second;
import first.*;
public class Test {
public static void main(String s[])
{
Provider pr = new Provider;
Parent p = pr.getValue;
System.out.println(p.getClass.getName);
// (Child)p - приведет к ошибке компиляции!
}
}
Результатом будет:
first.Child
То есть на самом деле в классе Test работа идет с экземпляром недоступного класса Child, что возможно, поскольку обращение к нему делается через открытый класс Parent. Попытка же выполнить явное приведение вызовет ошибку. Да, тип объекта "угадан" верно, но доступ к закрытому типу всегда запрещен.
Следующий пример:
public class Point {
private int x, y;
public boolean equals(Object o) {
if (o instanceof Point) {
Point p = (Point)o;
return p.x==x && p.y==y;
}
return false;
}
}
В этом примере объявляется класс Point с двумя полями, описывающими координаты точки. Обратите внимание, что поля полностью закрыты – private. Далее попытаемся переопределить стандартный метод equals таким образом, чтобы для аргументов, являющихся экземплярами класса Point, или его наследников (логика работы оператора instanceof ), в случае равенства координат возвращалось истинное значение. Обратите внимание на строку, где делается сравнение координат,– для этого приходится обращаться к private -полям другого объекта!
Тем не менее, такое действие корректно, поскольку private допускает обращения из любой точки класса, независимо от того, к какому именно объекту оно производится.
Другие примеры разграничения доступа в Java будут рассматриваться по ходу курса.
Объявление классов
Рассмотрим базовые возможности объявления классов.
Объявление класса состоит из заголовка и тела класса.
Заголовок класса
Вначале указываются модификаторы класса. Модификаторы доступа для класса уже обсуждались. Допустимым является public, либо его отсутствие – доступ по умолчанию.
Класс может быть объявлен как final. В этом случае не допускается создание наследников такого класса. На своей ветке наследования он является последним. Класс String и классы-обертки, например, представляют собой final -классы.
После списка модификаторов указывается ключевое слово class, а затем имя класса – корректный Java-идентификатор. Таким образом, кратчайшим объявлением класса может быть такой модуль компиляции:
class A { }
Фигурные скобки обозначают тело класса, но о нем позже.
Указанный идентификатор становится простым именем класса. Полное составное имя класса строится из полного составного имени пакета, в котором он объявлен (если это не безымянный пакет), и простого имени класса, разделенных точкой. Область видимости класса, где он может быть доступен по своему простому имени, – его пакет.
Далее заголовок может содержать ключевое слово extends, после которого должно быть указано имя (простое или составное) доступного не- final класса. В этом случае объявляемый класс наследуется от указанного класса. Если выражение extends не применяется, то класс наследуется напрямую от Object. Выражение extends Object допускается и игнорируется.
class Parent {
}
// = class Parent extends Object { }
final class LastChild extends Parent { }
// class WrongChild extends LastChild { }
// ошибка!!
Попытка расширить final -класс приведет к ошибке компиляции.
Если в объявлении класса A указано выражение extends B, то класс A называют прямым наследником класса B.
Класс A считается наследником класса B, если:
* A является прямым наследником B ;
* существует класс C, который является наследником B, а A является наследником C (это правило применяется рекурсивно).