Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Язык программирования JAVA.pdf
Скачиваний:
373
Добавлен:
02.05.2014
Размер:
2.57 Mб
Скачать

converted to PDF by BoJIoc

Начиная с этого момента программист, которому понадобилось узнать идентификатор небесного тела, должен вызвать метод id, возвращающий требуемое значение. У программиста не остается никакой возможности изменить идентификатор в сущности, за пределами класса его можно рассматривать как величину, доступную только для чтения. Данное поле может быть изменено только внутренними методами класса Body.

Методы, регулирующие доступ к внутренним данным класса, иногда называются методами доступа (accessor methods). С их помощью также можно (и, наверное, нужно) защитить поля name и orbits.

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

Упражнение 2.8

Объявите поля класса Vehicle с ключевым словом private и опишите соответствующие методы доступа. Для каких полей следует предусмотреть методы, изменяющие их значения, а для каких нет?

Упражнение 2.9

Объявите поля класса LinkedList с ключевым словом private и включите в класс соответствующие методы доступа. Для каких полей следует предусмотреть методы, изменяющие их значения, а для каких нет?

Упражнение 2.10

Включите в класс Vehicle метод changeSpeed для задания текущей скорости машины в соответствии с передаваемым значением и метод stop для обнуления скорости.

Упражнение 2.11

Включите в класс LinkedList метод для подсчета количества элементов в списке.

2.7. Ссылка this

Мы уже видели (на стр. ), как в начале работы конструктора происходит явный вызов другого конструктора класса. Специальная ссылка на объект this может также применяться внутри нестатических методов; она указывает на текущий объект, для которого был вызван данный метод. this чаше всего используется для передачи ссылки на текущий объект в качестве параметра для других методов. Предположим, в методе необходимо пополнить список объектов, ожидающих обслуживания. Такой вызов может выглядеть следующим образом:

Service.add(this);

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

class Name {

public String str; Name() {

str = “”;

}

converted to PDF by BoJIoc

}

равносильно следующему: this.str = “”;

Обычно this используется только в случае необходимости, то есть когда имя поля, к которому вы обращаетесь, скрывается объявлением переменной или параметра. Например:

class Moose {

String hairdresser;

Moose(String hairdresser) { this.hairdresser = hairdresser;

}

}

Поле hairdresser внутри конструктора скрывается присутствием одноименного параметра. Чтобы обратиться к полю hairdresser, а не к параметру, мы ставим перед именем ссылку this, указывая тем самым, что поле принадлежит к текущему объекту. Намеренное скрытие идентификаторов, осуществляемое подобным образом, может быть отнесено к

хорошему стилю программирования лишь при идиоматическом использовании в конструкторах и методах доступа.

Помимо ссылки this, может также применяться ссылка super, с помощью которой осуществляется доступ к скрытым полям и вызов переопределенных методов суперкласса. Ключевое слово super подробно рассматривается в разделе Переопределение методов и скрытие полей”.

2.8. Перегрузка методов

В языке Java каждый метод обладает определенной сигнатурой, которая представляет собой совокупность имени с количеством и типом параметров. Два метода могут иметь одинаковые имена, если их сигнатуры отличаются по количеству или типам параметров. Это называется перегрузкой (overloading), поскольку простое имя метода перегружаетсянесколькими значениями. Когда программист вызывает метод, компилятор по количеству и типу параметров ищет тот из существующих методов, сигнатура которого подходит лучше всех остальных. Приведем в качестве примера различные методы orbits Around нашего класса Body:

public Body orbitsAround() { return orbits;

}

public void orbitsAround(Body around) { orbits = around;

}

При подобном стиле программирования перегрузка служит для того, чтобы отличать выборку значения (параметры не передаются) от его задания (указывается аргумент, представляющий собой новое значение). Количество параметров в двух методах отличается, поэтому выбрать нужный метод будет несложно. Если orbitsAround вызывается без параметров, то используется метод, возвращающий текущее значение. Если orbitsAround вызывается с одним аргументом типа Body, то используется метод, задающий значение. Если же вызов не подходит ни под одну из этих сигнатур, то он является неверным, а программа не будет компилироваться.

converted to PDF by BoJIoc

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

Упражнение 2.12

Включите в класс Vehicle два новых метода: один в качестве параметра получает количество градусов, на которое поворачивает машина, а другой одну из констант

Vehicle.TURN_LEFT или Vehicle.TURN_RIGHT.

2.9. Статические члены

Класс содержит члены двух видов: поля и методы. Для каждого из них задается атрибут, определяющий возможности наследования и доступа (private, protected, public или package). Кроме того, каждый из членов при желании можно объявить как static.

Для статического члена создается всего один экземпляр, общий для всего класса, вместо построения его копий в каждом объекте класса. В случае статических переменных (переменных класса), это ровно одна переменная, независимо от того, сколько объектов было создано на основе класса (даже если ни одного). Образцом может служить поле nextID класса Body в приведенном выше примере.

Инициализация статических полей класса происходит до того, как они используются или запускается любой из его методов. В следующем примере метод unset может быть уверен в том, что перед использованием переменной UNSET ей было присвоено значение

Double.NaN:

class Value {

public static double UNSET = double.NaN;

private double V; public void unset() {

V = UNSET;

}

// ...

}

2.9.1. Блоки статической инициализации

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

массива часто должно выполняться одновременно с его инициализацией в операторах программы. Приведем пример инициализации небольшого массива с простыми числами:

class Primes {

protected static int[] knownPrimes = new int[4];

static {

knownPrimes[0] = 2;

for(int i = 1; i < knownPrimes.length; i++) knownPrimes[i] = nextPrime();

}

}

converted to PDF by BoJIoc

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

Что произойдет, если статический инициализатор класса X вызывает метод класса Y, а статический инициализатор Y, в свою очередь, вызывает метод из класса X для задания своих статических величин? Подобные циклические инициализации не могут быть надежно выявлены в процессе компиляции, поскольку в момент компиляции X класс Y может еще не существовать. Если возникает подобная ситуация, то статические инициализаторы X выполняются лишь до вызова метода Y. Когда Y, в свою очередь, обратится к методу X, то последний будет выполняться без завершения статической инициализации. Все статические поля X, для которых инициализация не была выполнена, будут иметь значения по умолчанию (false, ‘\u0000’, ноль или null в зависимости от типа).

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

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

2.9.2. Статические методы

Статические методы вызываются для целого класса, а не для каждого конкретного объекта, созданного на его основе. Подобные методы также называются методами класса. Статический метод может выполнять задачи, общие для всех объектов класса, — например, возвращать следующий серийный номер (в нашем примере с плеерами) или что-нибудь в этом роде.

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

За пределами класса статические методы обычно вызываются через имя класса, а не через ссылку на конкретный объект:

prime = Primes.nextPrime();

knownCnt = Primes.knownPrimes.length;

Упражнение 2.13

Включите в класс Vehicle статический метод, который возвращает максимальное значение идентификатора, использованное на данный момент.

2.10. Сборка мусора и метод finalize

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

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

на него отсутствуют ссылки в статических данных и в любой из переменных