Мои Конспекты
Главная | Обратная связь

...

Автомобили
Астрономия
Биология
География
Дом и сад
Другие языки
Другое
Информатика
История
Культура
Литература
Логика
Математика
Медицина
Металлургия
Механика
Образование
Охрана труда
Педагогика
Политика
Право
Психология
Религия
Риторика
Социология
Спорт
Строительство
Технология
Туризм
Физика
Философия
Финансы
Химия
Черчение
Экология
Экономика
Электроника

Используйте интерфейсы только для определения типов





Помощь в ✍️ написании работы
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой

 

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

Среди интерфейсов, которые не отвечают этому критерию, числится так назы­ваемый интерфейс констант (constant interface). Он не имеет методов и содер­жит исключительно поля static final, передающие константы. Классы, в которых эти константы используются, реализуют данный интерфейс для того, чтобы исклю­чить необходимость в добавлении к названию констант названия класса. Приведем пример:

// Шаблон интерфейса констант - не использоваты!

public interface РhуsiсаlСопstапts

// Число Авогадро (1/моль)

static final double AVOGADROS NUMBER = 6.02214199е23;

 

 

 

// Постоянная Больцмана (Дж/К)

static final double BOLTZMANN_CONSTANT=1.3806503е-23;

// Масса электрона (кг)

static final double ELECTRON MASS=9.10938188е-31;

 

Шаблон интерфейса констант представляет собой неудачный вариант ис­пользования интерфейсов. Появление внутри класса каких-либо констант является деталью реализации. Реализация интерфейса констант приводит к утечке таких дета­лей во внешний АРI данного класса. То, что класс реализует интерфейс констант, для пользователей класса не представляет никакого интереса. На практике это может даже сбить их с толку. Хуже того, это является неким обязательством: если в будущих версиях класс поменяется так, что ему уже не будет нужды использовать данные кон­станты, он все равно должен будет реализовывать этот интерфейс для обеспечения совместимости на уровне двоичных кодов (binary compatibility). Если же интерфейс констант реализует неокончательный класс; константами из этого интерфейса будет засорено пространство имен всех его подклассов.

В библиотеках для платформы Java есть несколько интерфейсов с константами, например jауа.io.ObjectSt reamConstants. Подобные интерфейсы нужно восприни­мать как отклонение от нормы, и подражать им не следует.

Для передачи констант существует несколько разумных способов. Если констан­ты сильно связаны с имеющимся классом или интерфейсом, вы должны добавить их непосредственно в этот класс или интерфейс. Например, все классы-оболочки в биб­лиотеках платформы Java, связанные с числами, такие как Integer и Float, предостав­ляют константы МIN_VALUE и MAX_VALUE. Если же константы лучше рассматривать как члены перечисления, то передавать их нужно с помощью класса перечисления (статья 21). В остальных случаях вы должны передавать константы с помощью вспо­могательнoго класса (utility c!ass), не имеющего экземпляров (статья 3). Представим вариант вспомогательного класса для предыдущего примера PhysicalConstants:

// Вспомогательный класс для констант

public class PhysicalConstants {

private PhysicalConstants() { }

// Предотвращает появление экэемпляра

public static final double AVOGADROS_NUMBER =6.02214199е23;

public static final doubleBOLTZMANN_CONSTANT =1.3806503е-23;

 

public static final double ELECTRON_MASS =9.10938188е-31;

}

 

Хотя представление PhysicalConstants в виде вспомогательного класса требует, чтобы клиенты связывали названия констант с именем класса, это не большая цена за получение осмысленного API. Возможно, что со временем язык Java позволит

 

 

 

осуществлять импорт статических полей. Пока же вы можете сократить размер программы, поместив часто используемые константы в локальные переменные или закрытые статические поля, например:

 

рrivate static final double РI = Math. PI;

 

Таким образом, интерфейсы нужно использовать только для определения типов. Их не 'следует применять для передачи констант.

 

Предпочитайте статические классы-члены нестатическим

 

 

Класс называется вложенным (nested), если он определен внутри другого класса.

Вложенный класс должен создаваться только для того, чтобы обслуживать окружаю­щий его класс. Если вложенный класс оказывается полезен в каком-либо ином кон­тексте, он должен стать классом верхнего уровня. Существуют четыре категории вложенных классов: статический класс-член (static member class), нестатический класс-член (nonstatic member class), анонимный класс (anonymoиs class) и локальный класс (local class). За исключением первого, остальные категории классов называются внутренними (inner class). В этой статье рассказывается о том, когда и какую катего­рию вложенного класса нужно использовать и почему.

Статический класс-член - это простейшая категория вложенного класса. Лучше всего рассматривать его как обычный класс, который декларирован внутри другого класса и имеет доступ ко всем членам окружающего его класса, даже к закрытым. Статический класс-член является статическим членом своего внешнего класса и подчи­няется тем же правилам доступа, что и остальные статические члены. Если он декла­рирован как закрытый, доступ к нему имеет лишь окружающий его класс, и т. д.

В одном из распространенных вариантов статический класс-член используется как открытый вспомогательный класс, который пригоден для применения, только когда есть внешний класс. Например, рассмотрим перечисление, описывающее опе­рации, которые может выполнять калькулятор (статья 21). Класс Operation должен быть открытым статическим классом-членом класса Calculator. Клиенты класса Calculator могут ссылаться на операции, выполняемые калькулятором, используя такие имена, как Calculator.Ореration.PLUS или Calculator.Ореration.MINUS. Этот вариант приводится ниже.

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

 

 

 

экземпляром класса-контеинера (enclosing instance). Из метода в экземпляре неста­тического класса-члена можно вызывать методы содержащего его экземпляра, либо, используя специальную конструкцию this [JLS 15.8.4], можно получить ссылку на включающий экземпляр. Если экземпляр вложенного класса может существовать в отрыве от экземпляра внешнего класса, то вложенный класс не может быть неста­тическим классом-членом: нельзя создать экземпляр нестатического класса-члена, не создав включающего его экземпляра.

Связь между экземпляром нестатического класса-члена и включающим его эк-

земпляроМ устанавливается при создании первого, и после этого поменять ее нельзя. Обычно эта связь задается автоматически путем вызова конструктора нестатического класса-члена из экземпляра метода во внешнем классе. Иногда можно установить связь вручную, используя выражение enclosinglnstance.newMemberClass(args). Как можно предположить, эта связь занимает место в экземпляре нестатического класса­-члена и увеличивает время его создания.

Нестатические классы-члены часто используются для определения адаптера (Adapter) [Сатта95, стр. 139], при содействии которого экземпляр внешнего класса воспринимается своим внутренним классом как экземпляр некоторого класса, не имеющего к нему отношения. Например, в реализациях интерфейса Мар нестатиче­ские классы-члены обычно применяются для создания представлении /(оллекции (collection view), возвращаемых методами keySet, entrySet и values интерфейса Мар. Аналогично, в реализациях интерфейсов коллекций, таких как Set и List, нестатиче­ские классы-члены обычно используются для создания итераторов:

// Типичный вариант использования нестатического класса-члена

public class MySet extends AbstractSet {

// Основная часть класса опущена

publiC Iterator iterator() {

return new Mylterator(); }

private class Mylterator implements Iterator {

}

}

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

 

 

 

 

Закрытые статические классы-члены обычно должны представлять составные части объекта, доступ к которым осуществляется через внешний класс. Например, рассмотрим экземпляр класса Мар, который сопоставляет ключи и значения. Внутри экземпляра Мар для каждой пары ключ/значение обычно создается объект Entry. Хотя каждая такая запись ассоциируется со схемой, клиенту не надо обращаться к собственным методам этой записи (geyKey, getValue и setValue). Следовательно, использовать нестатические классы-члены для представления отдельных записей в схеме Мар было бы расточительностью, самое лучшее решение - закрытый статиче­ский класс-член. Если в декларации этой записи вы случайно пропустите модификатор statlc, схема будет работать, но каждая запись будет содержать ненужную ссылку на общую схему, напрасно занимая время и место в памяти.

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

Анонимные классы в языке программирования Java не похожи ни на какие другие.

Анонимный класс не имеет имени. Он не является членом содержащего его класса. Вместо того чтобы быть декларированным с остальными членами класса, он одно­временно декларируется и порождает экземпляр в момент использования. Анонимный класс можно поместить в любом месте программы, где разрешается применять выраже­ния. В зависимости от местоположения анонимный класс ведет себя как статический либо как нестатический класс-член: в нестатическом контексте появляется окружаю­щий его экземпляр.

Применение анонимных классов имеет несколько ограничений. Поскольку аноним­ный класс одновременно декларируется и порождает экземпляр, его можно использо­вать, только когда его экземпляр должен порождаться лишь в одном месте программы. Анонимный класс не имеет имени, поэтому может применяться только в том случае, если после порождения экземпляра не нужно на него ссылаться. Анонимный класс обычно реализует лишь методы своего интерфейса или суперкласса. Он не объявляет каких-либо новых методов, так как для доступа к ним нет поименованного типа. По­скольку анонимные классы стоят среди выражений, они должны быть очень коротки­ми, возможно, строк двадцать или меньше. Использование более длинных анонимных Классов может усложнить про грамму с точки зрения ее чтения.

Анонимный класс обычно служит для создания объекта функции (function object), такого как экземпляр класса Comparator. Например, при вызове следующего метода строки в массиве, будут отсортированы по их длине:

// Типичный пример использования анонимного класса

Arrays.sort(args, new Comparator() {

public int compare(Object o1, Object o2) {

return ((String)o1).length() – ((String)o2).length();

} );

 

 

 

Другой распространенный случай использования анонимного класса - создание объекта процесса (process object), такого как экземпляры классов Thread, Runnable или ТiтerTask. Третий вариант: в статическом методе генерации (см. метод intArray­AsList в статье 16). Четвертый вариант: инициализация открытого статического поля final, которое соответствует сложному перечислению типов, когда для каждого экземпляра в перечислении требуется отдельный подкласс (см. класс Operation в статье 21). Если, как было рекомендовано ранее, класс Operation будет статическим членом класса Calculator, то отдельные константы класса Operation окажутся дваж­ды вложенными классами:

 

// Типичный пример использования открытого

// статического класса-члена

public class Calculator {

public static abstract class Operation{

private final String name;

Operation(String пате) { this.name = name; }

public String toString() { return this.name; }

// Выполняет арифметическую операцию, представленную

// данной константой

abstract double eval(double х, double у);

// Дважды вложенные анонимные классы

public static final Operation PLUS = new Operation("+"){

double eval(double х, double у) { return х + у; }

};

public static final Operation MINUS = new Operation("-") {

double eval(double х, double у) {геturn х - у; }

};

public static final Operation TIMES = new Operation("*"){

double eval(double х, double у) { , return х * у; }

};

public static final Operation DIVIDE = new Operat1on("/"){

double eval(double х, double у) { return х / у; }

 

};

}

// Возвращает результат указанной операции

public double calculate(double х, Operation ор, double у) {

геturn op.eval(x, у);

}

}

 

 

 

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

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

 

 

 

 

Глава 5

Доверь свою работу ✍️ кандидату наук!
Поможем с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой



Поиск по сайту:







©2015-2020 mykonspekts.ru Все права принадлежат авторам размещенных материалов.