АБОБА. Справочник по программированию на Java Методическое пособие
Скачать 242.41 Kb.
|
Возврат объектовМетод может возвращать любой тип данных, в том числе созданные типы классов. Например, в следующей программе метод icrByTen() возвращает объект, в котором значение переменной a на 10 больше значения этой переменной в вызывающем объекте. // Возвращение объекта. class Test { int a; Test(int i) { a = i; } Test incrByTen() { Test temp = new Test(a+10); return temp; } } class RetOb { public static void main(String args[]) { Test ob1 = new Test(2); Test ob2; ob2 = ob1.incrByTen(); System.out.println("ob1.a: " + ob1.a); System.out.println("ob2.a: " + ob2.a); ob2 = ob2.incrByTen(); System.out.println("ob2.a после второго увеличения значения: " + ob2.a); } } Эта программа генерирует следующий вывод: ob1.a: 2 ob2.a: 12 ob2.a после второго увеличения значения: 22 Как видите, при каждом вызове метода incrByTen() программа создает новый объект и возвращает ссылку на него вызывающей процедуре. Приведенная программа иллюстрирует еще один важный момент: поскольку все объекты распределяются динамически с помощью операции new, программисту не нужно беспокоиться о том, чтобы объект не вышел за пределы области определения, т.к. выполнение метода, в котором он был создан, прекращается. Объект будет существовать до тех пор, пока где-либо в программе будет существовать ссылка на него. При отсутствии какой-либо ссылки на него объект будет уничтожен во время следующей уборки мусора. Введение в управление доступомКак вы уже знаете, инкапсуляция связывает данные с манипулирующим ими кодом. Однако инкапсуляция предоставляет еще один важный атрибут: управление доступом. Посредством инкапсуляции можно управлять тем, какие части программы могут получать доступ к членам класса. Управление доступом позволяет предотвращать злоупотребления. Например, предоставляя доступ к данным только посредством четко определенного набора методов, можно предотвратить злоупотребление этими данными. Таким образом, если класс реализован правильно, он создает “черный ящик”, который можно использовать, но внутренний механизм которого защищен от повреждения. Однако представленные ранее классы не полностью соответствуют этой цели. Например, рассмотрим класс Stack, представленный в конце главы 6. Хотя методы push() и pop() действительно предоставляют управляемый интерфейс стека, этот интерфейс не обязателен для использования. То есть другая часть программы может обойти эти методы и обратиться к стеку непосредственно. Понятно, что в “плохих руках” эта возможность может приводить к проблемам. В этом разделе мы представим механизм, с помощью которого можно строго управлять доступом к различным членам класса. Способ доступа к члену класса определяется спецификатором доступа, который изменяет его объявление. В Java определен обширный набор спецификаторов доступа. Некоторые аспекты управления доступом связаны главным образом с наследованием и пакетами. Спецификаторами доступа Java являются public (общедоступный), private (приватный) и protected (защищенный). Java определяет также уровень доступа, предоставляемый по умолчанию. Спецификатор protected применяется только при использовании наследования. Начнем с определения спецификаторов public и private. Когда член класса изменяется спецификатором доступа public, он становится доступным для любого другого кода. Когда член класса указан как private, он доступен только другим членам этого же класса. Теперь вам должно быть понятно, почему методу main() всегда предшествует спецификатор public. Этот метод вызывается кодом, расположенным вне данной программы – т.е. системой времени выполнения Java. При отсутствии спецификатора доступа по умолчанию член класса считается общедоступным внутри своего собственного пакета, но недоступным для кода, расположенного вне этого пакета. В уже разработанных нами классах все члены класса использовали режим доступа, определенный по умолчанию, который, по сути, является общедоступным. Однако, как правило, это не будет соответствовать реальным требованиям. Обычно будет требоваться ограничить доступ к членам данных класса – предлагая доступ только через методы. Кроме того, в ряде случаев придется определять приватные методы класса. Спецификатор доступа предшествует остальной спецификации типа члена. То есть оператор объявления члена должен начинаться со спецификатора доступа. Например: public int i; private double j; private int myMethod(int a, char b) { // ... Чтобы влияние использования общедоступного и приватного доступа было понятно, рассмотрим следующую программу: /* Эта программа демонстрирует различие между спецификаторами public и private. */ class Test { int a; // доступ, определенный по умолчанию public int b; // общедоступный доступ private int c; // приватный доступ // методы доступа к c void setc(int i) { // установка значения переменной c c = i; } int getc() { // получение значения переменной c return c; } } class AccessTest { public static void main(String args[]) { Test ob = new Test(); // Эти операторы правильны, a и b доступны непосредственно ob.a = 10; ob.b = 20; // Этот оператор неверен и может вызвать ошибку // ob.c = 100; // Ошибка! // Доступ к объекту c должен осуществляться посредством методов его класса ob.setc(100); // OK System.out.println("a, b, и c: " + ob.a + " " + ob.b + " " + ob.getc()); } } Как видите, внутри класса Test использован метод доступа, заданный по умолчанию, что в данном примере равносильно указанию доступа public. Объект b явно указан как public. Объект c указан как приватный. Это означает, что он недоступен для кода, переделенного вне его класса. Поэтому внутри класса AccessTest объект c не может применяться непосредственно. Доступ к нему должен осуществляться посредством его общедоступных методов setc() и getc(). Удаление символа комментария из начала строки: // ob.c = 100; // Ошибка! , сделало бы компиляцию этой программы невозможной из-за нарушений правил доступа. |