49

49


Класс сам определяет, кому разрешен доступ к его членам. Не существует волшебного способа «ворваться» внутрь него. Код из другого пакета не может запросто обратиться к пакету и рассчитывать, что ему вдруг станут доступны все члены: protected, private и доступные в пакете. Получить доступ можно лишь несколькими «законными» способами:

•        Объявить член класса открытым (public), то есть доступным для кого угод­но и откуда угодно.

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

•        Как вы увидите в главе 7, где рассказывается о наследовании, производ­ный класс может получить доступ к защищенным (protected) членам ба­зового класса вместе с открытыми членами public (но не к приватцым членам private). Такой класс может пользоваться доступом в пределах па­кета только в том случае, если второй класс принадлежит тому же пакету (впрочем, пока на наследование и доступ protected можно не обращать внимания).

•        Предоставить «методы доступа», то есть методы для чтения и модифика­ции значения. С точки зрения ООП этот подход является предпочтитель­ным, и именно он используется в технологии JavaBeans.

public

При использовании ключевого слова public вы фактически объявляете, что сле­дующее за ним объявление члена класса доступно для всех, и прежде всего для клиентских программистов, использующих библиотеку. Предположим, вы оп­ределили пакет dessert, содержащий следующий компилируемый модуль:

// access/dessert/Cookie.java 11 Создание библиотеки, package access.dessert.

public class Cookie { public CookieO {

System.out.println("Конструктор Cookie");

}

void biteO { System out printlnCbite"); } } /// ~

Помните, что файл Cookie.java должен располагаться в подкаталоге dessert каталога с именем access (соответствующем данной главе книги), а последний должен быть включен в переменную CLASSPATH. Не стоит полагать, будто Java всегда начинает поиск с текущего каталога. Если вы не укажете символ . (точка) в переменной окружения CLASSPATH в качестве одного из путей по­иска, то Java и не заглянет в текущий каталог.

Если теперь написать программу, использующую класс Cookie:

// access/Dinner java // Использование библиотеки import access.dessert *;

public class Dinner {

public static void main(Stnng[] args) { Cookie x = new CookieO: //! x.biteO; // Обращение невозможно

}

} /* Output: Конструктор Cookie */// ~

то можно создать объект Cookie, поскольку конструктор этого класса объявлен открытым (public) и сам класс также объявлен как public. (Понятие открытого класса мы позднее рассмотрим чуть подробнее.) Тем не менее метод bite() этого класса недоступен в файле Dinner.java, поскольку доступ к нему предоставляет­ся только в пакете dessert. Так компилятор предотвращает неправильное ис­пользование методов.

Пакет по умолчанию

С другой стороны, следующий код работает, хотя на первый взгляд он вроде бы нарушает правила:

//• access/Cake java

// Обращение к классу из другого компилируемого модуля

class Cake {

public static void mainCString[] args) { Pie x = new PieO, x f():

}

} /* Output. Pie f() */// ~

Второй файл в том же каталоге:

//• access/Pie.java

// Другой класс

class Pie { void f() { System.out.pnntlnC'Pie.fO"): }

} ///:-

Вроде бы эти два файла не имеют ничего общего, и все же в классе Cake мож­но создать объект Pie и вызвать его метод f()! (Чтобы файлы компилировались, переменная CLASSPATH должна содержать символ точки.) Естественно было бы предположить, что класс Pie и метод f() имеют доступ в пределах пакета и поэтому закрыты для Cake. Онидействительно обладают доступом в преде­лах пакета —здесь все верно. Однако их доступность в классе Cake.java объяс­няется тем, что они находятся в одном каталоге и не имеют явно заданного име­ни пакета. Java по умолчанию включает такие файлы в «пакет по умолчанию» для текущего каталога, поэтому они обладают доступом в пределах пакета к дру­гим файлам в этом каталоге.

private

Ключевое слово private означает, что доступ к члену класса не предоставляется никому, кроме методов этого класса. Другие классы того же пакета также не мо­гут обращаться к private-членам. На первый взгляд вы вроде бы изолируете класс даже от самого себя. С другой стороны, вполне вероятно, что пакет соз­дается целой группой разработчиков; в этом случае private позволяет изме­нять члены класса, не опасаясь, что это отразится на другом классе данного пакета.

Предлагаемый по умолчанию доступ в пределах пакета часто оказывается достаточен для сокрытия данных; напомню, что такой член класса недоступен пользователю пакета. Это удобно, так как обычно используется именно такой уровень доступа (даже в том случае, когда вы просто забудете добавить специ­фикатор доступа). Таким образом, доступ public чаще всего используется тогда, когда вы хотите сделать какие-либо члены класса доступными для программи- ста-клиента. Может показаться, что спецификатор доступа private применяется редко и можно обойтись и без него. Однако разумное применение private очень важно, особенно в условиях многопоточного программирования (см. далее).

Пример использования private:

II- access/IceCream.java

// Демонстрация ключевого слова private.

class Sundae {

private SundaeO {} static Sundae makeASundaeO { return new SundaeO;

}

}

public class IceCream {

public static void main(String[] args) { III Sundae x = new SundaeO; Sundae x = Sundae makeASundae();

}

} ///-

Перед вами пример ситуации, в которой private может быть очень полезен: предположим, вы хотите контролировать процесс создания объекта, не разре­шая посторонним вызывать конкретный конструктор (или любые конструкто­ры). В данном примере запрещается создавать объекты Sundae с помощью конст­руктора; вместо этого пользователь должен использовать метод makeASundae().

Все «вспомогательные» методы классов стоит объявить как private, чтобы предотвратить их случайные вызовы в пакете; тем самым вы фактически запре­щаете изменение поведения метода или его удаление.

То же верно и к private-полям внутри класса. Если только вы не собираетесь предоставить доступ пользователям к внутренней реализации (а это происхо­дит гораздо реже, чем можно себе представить), объявляйте все поля своих классов со спецификатором private.

Report Page