Жан-Пьер Баблон
1.Базовые типы данных и литералы. Операторы. Классы-оболочки.Операторы управления.
В языке Java используются базовые типы данных, значения которых разме- щаются в стековой памяти (stack). Эти типы обеспечивают более высокую производительность вычислений по сравнению с объектами. Кроме этого, для каждого базового типа имеются классы-оболочки, которые инкапсулируют данные базовых типов в объекты, располагаемые в динамической памяти (heap).
В Java используются целочисленные литералы, например: 35 – целое десятичное число, 071 – восьмеричное значение, 0х51 – шестнадцатеричное значение. Целочисленные литералы по умолчанию относятся к типу int. Если необходимо определить длинный литерал типа long, в конце указывается символ L (например: 0xffffL). Если значение числа больше значения, помещающегося в int (2147483647), то Java автоматически предполагает, что оно типа long. Литералы с плавающей точкой записываются в виде 1.618 или в экспоненци- альной форме 0.112E-05 и относятся к типу double, таким образом, действи- тельные числа относятся к типу double. Если необходимо определить литерал типа float, то в конце литерала следует добавить символ F. Символьные литералы определяются в апострофах ('a', '\n', '\141', '\u005a' ). Для раз- мещения символов используется формат Unicode, в соответствии с которым для каждого символа отводится два байта. В формате Unicode первый байт содержит код управляющего символа или национального алфавита, а второй байт соответ- ствует стандартному ASCII коду, как в C++. Любой символ можно представить в виде '\ucode', где code представляет двухбайтовый шестнадцатеричный код символа. Java поддерживает управляющие символы, не имеющие графического изображения; '\n'– новая строка, '\r' – переход к началу, '\f' – новая страница, '\t'– табуляция, '\b' – возврат на один символ, '\uxxxx' – шестнадцате- ричный символ Unicode, '\ddd'– восьмеричный символ и др. Начиная с J2SE 5.0 используется формат Unicode 4.0. Поддержку четырехбайтным символам обеспечивает наличие специальных методов в классе Character. К литералам относятся булевские значения true и false, а также null – значение по умолчанию для ссылки на объект. При инициализации строки всегда создается объект класса String – это не массив символов и не строка. Строки, заключенные в двойные апострофы, считаются литералами и размещаются в пуле литералов, но в то же время такие строки представляют собой объекты.
Кроме базовых типов данных, в языке Java широко используются соответ- ствующие классы-оболочки (wrapper-классы) из пакета java.lang: Boolean, Character, Integer, Byte, Short, Long, Float, Double. Объекты этих классов могут хранить те же значения, что и соответствующие им базовые типы.
Операторы управления Оператор выбора if имеет следующий синтаксис: if (boolexp) { /*операторы*/} //1 else { /*операторы*/ } //2
2.
Массивы.
Массив представляет собой объект, где имя массива является объектной ссылкой. Элементами массива могут быть значения базового типа или объекты. Индексирование элементов начинается с нуля. Все массивы в языке Java являются динамическими, поэтому для создания массива требуется выделение памяти с помощью оператора new или прямой инициализации. Значения элементов неини- циализированного массива, для которого выделена память, устанавливаются в значения по умолчанию для массива базового типа или null для массива объект- ных ссылок. Для объявления ссылки на массив можно записать пустые квадратные скобки после имени типа, например: int a[]. Аналогичный результат получится при записи int[] a.
Многомерных массивов в Java не существует, но можно объявлять массив массивов. Для задания начальных значений массивов существует специальная форма инициализатора, например: int arr[][] = { { 1 }, { 2, 3 }, { 4, 5, 6 }, { 7, 8, 9, 0 } };
3. Класс Маth.
Класс java.lang.Math содержит только статические методы для физиче- ских и технических расчетов, а также константы E и PI.
Все методы класса вызываются без создания экземпляра класса (создать эк- земпляр класса Math невозможно). В классе определено большое количество ме- тодов для математических вычислений, а также ряд других полезных методов, таких как floor(), ceil(), rint(), round(), max(), min(), которые выполняют задачи по округлению, поиску экстремальных значений, нахождению ближайшего целого и т.д.
4.Переменные класса и константы. Ограничение доступа. Конструкторы. Методы.
Классы инкапсулируют переменные и методы – члены класса. Переменные класса объявляются в нем следующим образом: cпецификатор тип имя; В языке Java могут использоваться статические переменные класса, объявлен- ные один раз для всего класса со спецификатором static и одинаковые для всех экземпляров (объектов) класса, или переменные экземпляра класса, создаваемые для каждого объекта класса. Поля класса объявляются со спецификаторами до- ступа public, private, protected или по умолчанию без спецификатора. Кроме данных – членов класса, в методах класса используются локальные пере- менные и параметры методов. В отличие от переменных класса, инкапсули- руемых нулевыми элементами, переменные методов не инициализируются по умолчанию.
Переменные со спецификатором final являются константами. Специфи- катор final можно использовать для переменной, объявленной в методе, а также для параметра метода
Язык Java предоставляет несколько уровней защиты, обеспечивающих возможность настройки области видимости данных и методов. Из-за наличия пакетов Java работает с четырьмя категориями видимости между элементами классов: по умолчанию – дружественные члены класса доступны классам, находящимся в том же пакете; private – члены класса доступны только членам данного класса; protected – члены класса доступны классам, находящимся в том же пакете, и подклассам – в других пакетах; public – члены класса доступны для всех классов в этом и других пакетах.
Если у элемента вообще не указан модификатор уровня доступа, то такой элемент будет виден и доступен из подклассов и классов того же пакета. Именно такой уровень доступа используется по умолчанию. Если же необходимо, чтобы элемент был доступен из другого пакета, но только подклас- сам того класса, которому он принадлежит, нужно объявить такой элемент со спецификатором protected.
Конструктор это метод, который автоматически вызывается при создании объекта класса и выполняет действия по инициализации объекта. Конструктор имеет то же имя, что и класс; вызывается не по имени, а только вместе с ключе- вым словом new при создании экземпляра класса. Конструктор не возвращает значение, но может иметь параметры и быть перегружаемым. Деструкторы в языке Java не используются, объекты уничтожаются сборщи- ком мусора после прекращения их использования (потери ссылки). Аналогом де- структора является метод finalize(). Исполняющая среда языка Java будет вызывать его каждый раз, когда сборщик мусора будет уничтожать объект класса, которому не соответствует ни одна ссылка
Все функции Java объявляются только внутри классов и называются метода- ми. Простейшее определение метода имеет вид: returnType methodName(список_параметров) { // тело метода return value; // если нужен возврат значения (returnType не void) }
5.Статические методы и поля. Модификатор native. Модификатор synchronized. Логические блоки.
Поля данных, объявленные в классе как static, являются общими для всех объектов класса и называются переменными класса. Если один объект изменит значение такого поля, то это изменение увидят все объекты.
Вызов статического метода также следует осуществлять с помощью указания: ClassName.methodName().
Приложение на языке Java может вызывать методы, написанные на языке С++. Такие методы объявляются с ключевым словом native, которое сообщает компи- лятору, что метод реализован в другом месте. Например: public native int loadCripto(int num); Методы, помеченные native, можно переопределять обычными методами в подклассах.
При использовании нескольких потоков управления в одном приложении необходимо синхронизировать методы, обращающиеся к общим данным. Когда интерпретатор обнаруживает synchronized, он включает код, блокирующий доступ к данным при запуске потока и снимающий блок при его завершении. Вызов методов уведомления о возвращении блокировки объекта notifyAll(), notify() и метода остановки потока wait() класса Object (суперкласса для всех классов языка Java) предполагает использование модифи- катора synchronized, так как эти методы предназначены для работы с пото- ками.
При описании класса могут быть использованы логические блоки. Логиче- ским блоком называется код, заключенный в фигурные скобки и не принадлежа- щий ни одному методу текущего класса, например: { /* код */ } static { /* код */ } При создании объекта класса они вызываются последовательно, в порядке разме- щения, вместе с инициализацией полей как простая последовательность операто- ров, и только после выполнения последнего блока будет вызван конструктор класса. Операции с полями класса внутри логического блока до явного объявле- ния этого поля возможны только при использовании ссылки this, представляю- щую собой ссылку на текущий объект.
6.Параметризованные классы. Параметризованные методы. Методы с переменным числом параметров.
К наиболее важным новшествам версии языка J2SE 5 можно отнести появле- ние параметризованных (generic) классов и методов, позволяющих использовать более гибкую и в то же время достаточно строгую типизацию, что особенно важ- но при работе с коллекциями. Параметризация позволяет создавать классы, интерфейсы и методы, в которых тип обрабатывае- мых данных задается как параметр.
Объявление generic-типа в виде <T>, несмотря на возможность использо- вать любой тип в качестве параметра, ограничивает область применения разра- батываемого класса. Переменные такого типа могут вызывать только методы класса Object. Доступ к другим методам ограничивает компилятор, предупре- ждая возможные варианты возникновения ошибок. Чтобы расширить возможности параметризованных членов класса, можно ввести ограничения на используемые типы при помощи следующего объявления класса: public class OptionalExt <T extends Tип> { private T value; } Такая запись говорит о том, что в качестве типа Т разрешено применять толь- ко классы, являющиеся наследниками (суперклассами) класса Tип, и соответ- ственно появляется возможность вызова методов ограничивающих (bound) типов.
Параметризованный (generic) метод определяет базовый набор операций, ко- торые будут применяться к разным типам данных, получаемых методом в каче- стве параметра, и может быть записан, например, в виде: <T extends Тип> returnType methodName(T arg) {} <T> returnType methodName(T arg) {} Описание типа должно находиться перед возвращаемым типом. Запись пер- вого вида означает, что в метод можно передавать объекты, типы которых явля- ются подклассами класса, указанного после extends. Второй способ объявления метода никаких ограничений на передаваемый тип не ставит. Generic-методы могут находиться как в параметризованных классах, так и в обычных. Параметр метода может не иметь никакого отношения к параметру сво- его класса.
Возможность передачи в метод нефиксированного числа параметров позволя- ет отказаться от предварительного создания массива объектов для его последую- щей передачи в метод.
public class DemoVarargs {
public static int getArgCount(Integer... args)
{
if (args.length == 0) System.out.print("No arg=");
for (int i : args) System.out.print("arg:" + i + " ");
return args.length;
}
public static void main(String args[])
{
System.out.println("N=" + getArgCount(7, 71, 555));
Integer[] i = { 1, 2, 3, 4, 5, 6, 7 };
System.out.println("N=" + getArgCount(i));
System.out.println(getArgCount());
}
В результате выполнения этой программы будет выведено:
arg:7 arg:71 arg:555 N=3
arg:1 arg:2 arg:3 arg:4 arg:5 arg:6 arg:7 N=7
No arg=0
7.Перечисления. Аннотации.
Типобезопасные перечисления (typesafe enums) в Java представляют собой классы и являются подклассами абстрактного класса java.lang.Enum. При этом объекты перечисления инициализируются прямым объявлением без помощи оператора new. При инициализации хотя бы одного перечисления происходит инициализация всех без исключения оставшихся элементов данного перечисления.
Перечисление как подкласс класса Enum может содержать поля, конструкто- ры и методы, реализовывать интерфейсы. Каждый тип enum может использо- вать методы: static enumType[] values() – возвращает массив, содержащий все элементы перечисления в порядке их объявления; static T valueOf(Class<T> enumType, String arg) – возвра- щает элемент перечисления, соответствующий передаваемому типу и значению передаваемой строки; static enumType valueOf(String arg) – возвращает элемент пере- числения, соответствующий значению
передаваемой строки; int ordinal() – возвращает позицию элемента перечисления.
8.Наследование. Использование final.
Отношение между классами, при котором характеристики одного класса (су- перкласса) передаются другому классу (подклассу) без их повторного описания, называется наследованием.
Подкласс наследует переменные и методы суперкласса, используя ключевое слово extends. Класс может также реализовывать любое число интерфейсов, используя ключевое слово – implements. Подкласс имеет прямой доступ ко всем открытым переменным и методам родительского класса, как будто они находятся в подклассе. Исключение составляют члены класса, помеченные private (во всех случаях) и «по умолчанию» для подкласса в другом пакете. В любом случае (даже если ключевое слово extends отсутствует) класс автома- тически наследует свойства суперкласса всех классов – класса Object.
Нельзя создать подкласс для класса, объявленного со спецификатором final
9.Использование super и this.
Ключевое слово super используется для вызова конструктора суперкласса и для доступа к члену суперкласса. Например: super(список_параметров);/* вызов конструктора суперкласса с передачей параметров или без нее*/ super.id = 71; /* обращение к атрибуту суперкласса */ super.getId(); // вызов метода суперкласса Вторая форма super используется для доступа из подкласса к переменной id суперкласса. Третья форма специфична для Java и обеспечивает вызов из под- класса переопределенного метода суперкласса, причем если в суперклассе этот метод не определен, то будет осуществляться поиск по цепочке наследования до тех пор, пока метод не будет найден. Каждый экземпляр класса имеет неявную ссылку this на себя, которая пе- редается также и методам. После этого метод «знает», какой объект его вызвал. Вместо обращения к атрибуту id в методах можно писать this.id, хотя и не обязательно, так как записи id и this.id равносильны.
10. Переопределение методов и полиморфизм. Полиморфизм и расширяемость.
Способность Java делать выбор метода, исходя из типа объекта во время вы- полнения, называется поздним связыванием. При вызове метода его поиск про- исходит сначала в данном классе, затем в суперклассе, пока метод не будет найден или не достигнут Object – суперкласс для всех классов. Если два метода с одинаковыми именами и возвращаемыми значениями находятся в одном классе, то списки их параметров должны отличаться. То же относится к методам, наследуемым из суперкласса. Такие методы являются пе- регружаемыми (overloading). При обращении вызывается тот метод, список па- раметров которого совпадает со списком параметров вызова. Если объявление метода подкласса полностью, включая параметры, совпадает с объявлением ме- тода суперкласса (порождающего класса), то метод подкласса переопределяет (overriding) метод суперкласса. Переопределение методов является основой концепции динамического связывания, реализующей полиморфизм. Когда пере- определенный метод вызывается через ссылку суперкласса, Java определяет, какую версию метода вызвать, основываясь на типе объекта, на который имеет- ся ссылка.
Все методы Java являются виртуальными (ключевое слово virtual, как в C++, не используется). Статические методы могут быть переопределены в подклассе, но не могут быть полиморфными, так как их вызов не затрагивает объекты. Их следует вызы- вать только с использованием имени класса.
В объектно-ориентированном программировании применение наследования предоставляет возможность расширения и дополнения программного обеспече- ния, имеющего сложную структуру с большим количеством классов и методов. В задачи базового класса в этом случае входит определение интерфейса (как спосо- ба взаимодействия) для всех наследников.
11. Статические методы и полиморфизм.
Переопределение статических методов класса не имеет практического смыс- ла, так как обращение к статическому атрибуту или методу осуществляется по- средством задания имени класса, которому они принадлежат. К статическим ме- тодам принципы «позднего связывания» неприменимы. При использовании ссыл- ки для доступа к статическому члену компилятор при выборе метода или поля учитывает тип ссылки, а не тип объекта, ей присвоенного.
12. Абстракция и абстрактные классы.
Абстрактные классы объявляются с ключевым словом abstract и содержат объявления абстрактных методов, которые не реализованы в этих классах, а будут реализованы в подклассах. Объекты таких классов создать нельзя, но можно со- здать объекты подклассов, которые реализуют эти методы. При этом допустимо объявлять ссылку на абстрактный класс, но инициализировать ее можно только объектом производного от него класса. Абстрактные классы могут содержать и полностью реализованные методы, а также конструкторы и поля данных. С помощью абстрактного класса объявляется контракт (требования к функци- ональности) для его подклассов.
13. Клонирование объектов. “Сборка мусора” и освобождение ресурсов.
Объекты в методы передаются по ссылке, в результате чего в метод передает- ся ссылка на объект, находящийся вне метода. Поэтому если в методе изменить значение поля объекта, то это изменение коснется исходного объекта. Во избежа- ние такой ситуации для защиты внешнего объекта следует создать клон (копию) объекта в методе. Класс Object содержит protected-метод clone(), осу- ществляющий побитовое копирование объекта производного класса. Однако сна- чала необходимо переопределить метод clone() как public для обеспечения возможности вызова из другого пакета. В переопределенном методе следует вы- звать базовую версию метода super.clone(), которая и выполняет собственно клонирование. Чтобы окончательно сделать объект клонируемым, класс должен реализовать интерфейс Cloneable. Интерфейс Cloneable не содержит мето- дов относится к помеченным (tagged) интерфейсам, а его реализация гарантирует, что метод clone() класса Object возвратит точную копию вызвавшего его объекта с воспроизведением значений всех его полей. В противном случае метод генерирует исключение CloneNotSupportedException. Следует отметить, что при использовании этого механизма объект создается без вызова конструкто- ра. В языке C++ аналогичный механизм реализован с помощью конструктора ко- пирования.
Когда никаких ссылок на объект не существует, то есть все ссылки на него вышли из области видимости программы, предполагается, что объект больше не нужен, и память, занятая объектом, может быть освобождена. “Сборка мусора” происходит нере- гулярно во время выполнения программы. Форсировать “сборку мусора” невоз- можно, можно лишь “рекомендовать” ее выполнить вызовом метода Sys- tem.gc() или Runtime.getRuntime().gc(), но виртуальная машина выполнит очистку памяти тогда, когда сама посчитает это удобным. Вызов ме- тода System.runFinalization() приведет к запуску метода finalize() для объектов утративших все ссылки.
14. Интерфейсы.
Интерфейсы подобны полностью абстрактным классам, но не являются клас- сами. Ни один из объявленных методов не может быть реализован внутри интер- фейса. В языке Java существуют два вида интерфейсов: интерфейсы, определяю- щие контракт для классов посредством методов, и интерфейсы, реализация кото- рых автоматически (без реализации методов) придает классу определенные свой- ства. К последним относятся, например, интерфейсы Cloneable и Serializ- able, отвечающие за клонирование и сохранение объекта в информационном потоке соответственно. Все объявленные в интерфейсе методы автоматически трактуются как public и abstract, а все поля – как public, static и final, даже если они так не объявлены. Класс может реализовывать любое число интерфейсов, указы- ваемых через запятую после ключевого слова implements, дополняющего определение класса. После этого класс обязан реализовать все методы, получен- ные им от интерфейсов, или объявить себя абстрактным классом. На множестве интерфейсов также определена иерархия наследования, но она не имеет отношения к иерархии классов. Определение интерфейса имеет вид: [public] interface Имя [extends Имя1, Имя2,…, ИмяN] { /*реализация интерфейса*/
15. Статический импорт.
Константы и статические методы класса можно использовать без указания принадлежности к классу, если применить статический импорт, как это показано в следующем примере. // пример # 10 : статический импорт: ImportDemo.java package chapt06; import static java.lang.Math.*;
public class ImportDemo {
public static void main(String[] args) { double radius = 3; System.out.println(2 * PI * radius); System.out.println(floor(cos(PI/3))); }
}
Если необходимо получить доступ только к одной константе класса или ин- терфейса, например Math.E, то статический импорт производится в следующем виде: import static java.lang.Math.E; import static java.lang.Math.cos;//для одного метода
16. Внутренние (inner) классы. Вложенные (nested) классы. Анонимные (anonymous).
Классы могут взаимодействовать друг с другом не только посредством насле- дования и использования ссылок, но и посредством организации логической структуры с определением одного класса в теле другого. В Java можно определить (вложить) один класс внутри определения другого класса, что позволяет группировать классы, логически связанные друг с другом, и динамично управлять доступом к ним. С одной стороны, обоснованное использо- вание в коде внутренних классов делает его более эффектным и понятным. С дру- гой стороны, применение внутренних классов есть один из способов сокрытия кода, так как внутренний класс может быть абсолютно недоступен и не виден вне класса-владельца. Внутренние классы также используются в качестве блоков про- слушивания событий (глава «События»). Одной из важнейших причин использо- вания внутренних классов является возможность независимого наследования внутренними классами. Фактически при этом реализуется множественное насле- дование со своими преимуществами и проблемами.
Нестатические вложенные классы принято называть внутренними (inner) классами. Доступ к элементам внутреннего класса возможен из внешнего класса только через объект внутреннего класса, который должен быть создан в коде ме- тода внешнего класса. Объект внутреннего класса всегда ассоциируется (скрыто хранит ссылку) с создавшим его объектом внешнего класса – так называемым внешним (enclosing) объектом.
Если не существует необходимости в связи объекта внутреннего класса с объ- ектом внешнего класса, то есть смысл сделать такой класс статическим. Вложенный класс логически связан с классом-владельцем, но может быть ис- пользован независимо от него. При объявлении такого внутреннего класса присутствует служебное слово static, и такой класс называется вложенным (nested). Если класс вложен в ин- терфейс, то он становится статическим по умолчанию. Такой класс способен наследовать другие классы, реализовывать интерфейсы и являться объектом наследования для любого класса, обладающего необходимыми правами доступа. В то же время статический вложенный класс для доступа к нестатическим членам и методам внешнего класса должен создавать объект внешнего класса, а напря- мую имеет доступ только к статическим полям и методам внешнего класса. Для создания объекта вложенного класса объект внешнего класса создавать нет необ- ходимости. Подкласс вложенного класса не способен унаследовать возможность доступа к членам внешнего класса, которыми наделен его суперкласс.
Анонимные (безымянные) классы применяются для придания уникальной функциональности отдельно взятому объекту для обработки событий, реализации блоков прослушивания и т.д. Можно объявить анонимный класс, который будет расширять другой класс или реализовывать интерфейс при объявлении одного, единственного объекта, когда остальным объектам этого класса будет соответ- ствовать реализация метода, определенная в самом классе. Объявление анонимно- го класса выполняется одновременно с созданием его объекта посредством опера- тора new. Анонимные классы эффективно используются, как правило, для реализации (переопределения) нескольких методов и создания собственных методов объекта. Этот прием эффективен в случае, когда необходимо переопределение метода, но создавать новый класс нет необходимости из-за узкой области (или одноразового) применения метода. Конструкторы анонимных классов нельзя определять и переопределять. Ано- нимные классы допускают вложенность друг в друга, что может сильно запутать код и сделать эти конструкции непонятными.
TypeQuest unique = new TypeQuest() {// анонимный класс #1
public void addNewType() { // новая реализация метода
System.out.println( "добавлен вопрос со свободным ответом");
}
};// конец объявления анонимного класса
TypeQuest – некий класс, мы не хочем из-за одного метода addNewType() создавать новый класс наследник, поэтому вот так переопределили метод
17. Класс String.
Каждая строка, создаваемая с помощью оператора new или с помощью лите- рала (заключённая в двойные апострофы), является объектом класса String. Особенностью объекта класса String является то, что его значение не может быть изменено после создания объекта при помощи какого-либо метода класса, так как любое изменение строки приводит к созданию нового объекта. При этом ссылку на объект класса String можно изменить так, чтобы она указывала на другой объект и тем самым на другое значение.
String concat(String s) или “+” – слияние строк; boolean equals(Object ob) и equalsIgnoreCase(String s) – сравнение строк с учетом и без учета регистра соответственно; int compareTo(String s) и compareToIgnoreCase(String s) – лексикографическое сравнение строк с учетом и без учета регистра. Метод осу- ществляет вычитание кодов символов вызывающей и передаваемой в метод строк и возвращает целое значение. Метод возвращает значение нуль в случае, когда equals() возвращает значение true; boolean contentEquals(StringBuffer ob) – сравнение строки и содержимого объекта типа StringBuffer; String substring(int n, int m) – извлечение из строки подстроки длины m-n, начиная с позиции n. Нумерация символов в строке начинается с нуля; String substring(int n) – извлечение из строки подстроки, начиная с позиции n; int length() – определение длины строки; int indexOf(char ch) – определение позиции символа в строке; static String valueOf(значение) – преобразование переменной базового типа к строке; String toUpperCase()/toLowerCase() – преобразование всех сим- волов вызывающей строки в верхний/нижний регистр; String replace(char с1, char с2) – замена в строке всех вхожде- ний первого символа вторым символом; String intern() – заносит строку в “пул” литералов и возвращает ее объектную ссылку; String trim() – удаление всех пробелов в начале и конце строки; char charAt(int position) – возвращение символа из указанной по- зиции (нумерация с нуля); boolean isEmpty() – возвращает true, если длина строки равна 0; byte[] getBytes(), getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) – извлечение символов строки в массив байт или символов;
static String format(String format, Object... args), format(Locale l, String format, Object... args) – генерирует форматированную строку, полученную с использованием формата, интернацио- нализации и др.; String[] split(String regex), split(String regex, int limit) – поиск вхождения в строку заданного регулярного выражения (раздели- теля) и деление исходной строки в соответствии с этим на массив строк. Во всех случаях вызова методов, изменяющих строку, создается новый объ- ект типа String.
18. Классы StringBuilder и StringBuffer.
Классы StringBuilder и StringBuffer являются “близнецами” и по своему предназначению близки к классу String, но, в отличие от по- следнего, содержимое и размеры объектов классов StringBuilder и StringBuffer можно изменять. Основным и единственным отличием StringBuilder от StringBuffer является потокобезопасность последнего. В версии 1.5.0 был добавлен непотоко- безопасный (следовательно, более быстрый в обработке) класс StringBuilder, который следует применять, если не существует вероятности использования объекта в конкурирующих потоках. С помощью соответствующих методов и конструкторов объекты классов StringBuffer, StringBuilder и String можно преобразовывать друг в друга. Конструктор класса StringBuffer (также как и StringBuilder) мо- жет принимать в качестве параметра объект String или неотрицательный раз- мер буфера. Объекты этого класса можно преобразовать в объект класса String методом toString() или с помощью конструктора класса String.
При создании объекта StringBuffer конструктор по умолчанию автомати- чески резервирует некоторый объем памяти (16 символов), что в дальнейшем поз- воляет быстро менять содержимое объекта, оставаясь в границах участка памяти, выделенного под объект. Размер резервируемой памяти при необходимости мож- но указывать в конструкторе. Если длина строки StringBuffer после измене- ния превышает его размер, то ёмкость объекта автоматически увеличивается, оставляя при этом резерв для дальнейших изменений. С помощью метода re- verse() можно быстро изменить порядок символов в объекте. Если метод, вызываемый объектом StringBuffer, производит измене- ния в его содержимом, то это не приводит к созданию нового объекта, как в случае объекта String, а изменяет текущий объект StringBuffer.
void setLength(int n) – установка размера буфера; void ensureCapacity(int minimum) – установка гарантированного минимального размера буфера; int capacity() – возвращение текущего размера буфера; StringBuffer append(параметры) – добавление к содержимому объ- екта строкового представления аргумента, который может быть символом, значе- нием базового типа, массивом и строкой; StringBuffer insert(параметры) – вставка символа, объекта или строки в указанную позицию; StringBuffer deleteCharAt(int index) – удаление символа; StringBuffer delete(int start, int end) – удаление подстроки; StringBuffer reverse() – обращение содержимого объекта. В классе присутствуют также методы, аналогичные мето
дам класса String, такие как replace(), substring(), charAt(), length(), getChars(), indexOf() и др.
19. Форматирование строк.
Для создания форматированного текстового вывода предназначен класс java.util.Formatter. Этот класс обеспечивает преобразование формата, позволяющее выводить числа, строки, время и даты в любом необходимом разра- ботчику виде. В классе Formatter объявлен метод format(), который преобразует пере- данные в него параметры в строку заданного формата и сохраняет в объекте типа Formatter. Аналогичный метод объявлен у классов PrintStream и PrintWriter. Кроме того, у этих классов объявлен метод printf() с парамет- рами идентичными параметрам метода format(), который осуществляет форма- тированный вывод в поток, тогда как метод format() сохраняет изменения в объ- екте типа Formatter. Таким образом, метод printf() автоматически ис- пользует возможности класса Fomatter и подобен функции printf() языка С. Класс Formatter преобразует двоичную форму представления данных в форматированный текст. Он сохраняет форматированный текст в буфере, содержимое которого можно получить в любой момент. Можно предоставить классу Formatter автоматическую поддержку этого буфера либо задать его явно при создании объекта. Существует возможность сохранения буфера класса Formatter в файле.
В классе объявлены следующие методы: Formatter format(String fmtString, Object...args) – форма- тирует аргументы, переданные в аргументе переменной длины args (количество аргументов в списке вывода не фиксировано), в соответствии со спецификатора- ми формата, содержащимися в fmtString. Возвращает вызывающий объект; Formatter format(Locale loc, String fmtString, Object...args) – форматирует аргументы, переданные в аргументе перемен- ной длины args, в соответствии со спецификаторами формата, содержащимися в fmtString. При форматировании используются региональные установки, за- данные в lос. Возвращает вызывающий объект; IOException ioException() – если объект, приемник отформатирован- ного вывода, генерирует исключение типа IOException, возвращает это ис- ключение. В противном случае возвращает null; Locale locale() – возвращает региональные установки вызывающего объекта; Appendable out() – возвращает ссылку на базовый объект-приемник для выходных данных; void flush() – переносит информацию из буфера форматирования и про- изводит запись в указанное место выходных данных, находящихся в буфере. Ме- тод чаще всего используется объектом класса Formatter, связанным с файлом; void close() – закрывает вызывающий объект класса Formatter, что приводит к освобождению ресурсов, используемых объектом. После закрытия объекта типа Formatter он не может использоваться повторно. Попытка исполь- зовать закрытый объект приводит к генерации исключения типа FormatterClosedEception; String toString() – возвращает объект типа String, содержащий от- форматированный вывод.
20. Регулярные выражения.
Pattern compile(String regex) – возвращает Pattern, который со- ответствует regex. Matcher matcher(CharSequence input) – возвращает Matcher, с помощью которого можно находить соответствия в строке input. boolean matches(String regex, CharSequence input) – про- веряет на соответствие строки input шаблону regex. String pattern() – возвращает строку, соответствующую шаблону. String[] split(CharSequence input) – разбивает строку input, учитывая, что разделителем является шаблон. String[] split(CharSequence input, int limit) – разбивает строку input на не более чем limit частей. С помощью метода matches() класса Pattern можно проверять на соот- ветствие шаблону целой строки, но если необходимо найти соответствия внутри строки, например, определять участки, которые соответствуют шаблону, то класс Pattern не может быть использован. Для таких операций необходимо использо- вать класс Matcher. Начальное состояние объекта типа Matcher не определено. Попытка выз- вать какой-либо метод класса для извлечения информации о найденном соответ- ствии приведет к возникновению ошибки IllegalStateException. Для того чтобы начать работу с объектом Matcher, нужно вызвать один из его методов: boolean matches() – проверяет, соответствует ли вся строка шаблону; boolean lookingAt() – пытается найти последовательность символов, начинающуюся с начала строки и соответствующую шаблону; boolean find() или boolean find(int start) – пытается найти по- следовательность символов, соответствующих шаблону, в любом месте строки. Параметр start указывает на начальную позицию поиска. Иногда необходимо сбросить состояние Matcher’а в исходное, для этого применяется метод reset() или reset(CharSequence input), который также устанавливает новую последовательность символов для поиска. Для замены всех подпоследовательностей символов, удовлетворяющих шаб- лону, на заданную строку можно применить метод replaceAll(String replacement). Для того чтобы ограничить поиск границами входной последовательности, применяется метод region(int start, int end), а для получения значе- ния этих границ – regionEnd() и regionStart(). С регионами связано не- сколько методов: Matcher useAnchoringBounds(boolean b) – если установлен в true, то начало и конец региона соответствуют символам ^ и $ соответственно.
boolean hasAnchoringBounds() – проверяет закрепленность границ. В регулярном выражении для более удобной обработки входной после- довательности применяются группы, которые помогают выделить части найден- ной подпоследовательности. В шаблоне они обозначаются скобками “(“ и “)”. Номера групп начинаются с единицы. Нулевая группа совпадает со всей найден- ной подпоследовательностью. Далее приведены методы для извлечения информа- ции о группах. int end() – возвращает индекс последнего символа подпоследовательно- сти, удовлетворяющей шаблону; int end(int group) – возвращает индекс последнего символа указанной группы; String group() – возвращает всю подпоследовательность, удовлетворя- ющую шаблону; String group(int group) – возвращает конкретную группу; int groupCount() – возвращает количество групп; int start() – возвращает индекс первого символа подпоследовательно- сти, удовлетворяющей шаблону; int start(int group) – возвращает индекс первого символа указанной группы; boolean hitEnd() – возвращает истину, если был достигнут конец вход- ной последовательности.
21. Интернационализация текста.
Класс java.util.Locale позволяет учесть особенности региональных представлений алфавита, символов и проч. Автоматически виртуальная машина использует текущие региональные установки операционной системы, но при необходимости их можно изменять. Для некоторых стран региональные параметры устанавливаются с помощью констант, например: Locale.US, Locale.FRANCE. Для других стран объект Locale нужно создавать с по- мощью конструктора: Locale myLocale = new Locale("bel", "BY"); Получить доступ к текущему варианту региональных параметров можно сле- дующим образом: Locale current = Locale.getDefault(); Если, например, в ОС установлен регион «Россия» или в приложении с помощью new Locale("ru", "RU"), то следующий код (при выводе результатов вы- полнения на консоль)
current.getCountry();//код региона
current.getDisplayCountry();//название региона
current.getLanguage();//код языка региона
current.getDisplayLanguage();//название языка региона
позволяет получить информацию о регионе в виде:
RU
Россия
ru
русский
Для создания приложений, поддерживающих несколько языков, существует целый ряд решений. Самое логичное из них – использование взаимодействия классов java.util.ResourceBundle и Locale. Класс ResourceBundle предназначен в первую очередь для работы с текстовыми файлами свойств (рас- ширение .properties). Каждый объект ResourceBundle представляет со- бой набор объектов соответствующих подтипов, которые разделяют одно и то же базовое имя, к которому можно получить доступ через поле parent. Следующий список показывает возможный набор соответствующих ресурсов с базовым име- нем text. Символы, следующие за базовым именем, показывают код языка, код страны и тип операционной системы. Например, файл text_de_CH.properties соответствует объекту Locale, заданному кодом языка немецкого (de) и кодом страны Швейцарии (CH).
Чтобы выбрать определенный объект ResourceBundle, следует вызвать метод ResourceBundle.getBundle(параметры). Следующий фрагмент выбирает text объекта ResourceBundle для объекта Locale, который соот- ветствует английскому языку, стране Канаде и платформе UNIX. Locale currentLocale = new Locale("en", "CA", "UNIX"); ResourceBundle rb = ResourceBundle.getBundle("text", currentLocale);
22. Иерархия и способы обработки. Оператор throw.Ключевое слово finally.
Исключительные ситуации (исключения) возникают во время выполнения программы, когда возникшая проблема не может быть решена в текущем контек- сте и невозможно продолжение работы программы. Примерами являются особо «популярные»: попытка индексации вне границ массива, вызов метода на нулевой ссылке или деление на нуль. При возникновении исключения создается объект, описывающий это исключение. Затем текущий ход выполнения приложения оста- навливается, и включается механизм обработки исключений. При этом ссылка на объект-исключение передается обработчику исключений, который пытается ре- шить возникшую проблему и продолжить выполнение программы. Если в классе используется метод, в котором может возникнуть проверяемая исключительная ситуация, но не предусмотрена ее обработка, то ошибка возникает еще на этапе компиляции. При создании такого метода программист должен включить в код обработку исключений, которые могут генерировать этот метод, или передать об- работку исключения на более высокий уровень методу, вызвавшему данный метод. Каждой исключительной ситуации поставлен в соответствие некоторый класс. Если подходящего класса не существует, то он может быть создан разра- ботчиком. Все исключения являются наследниками суперкласса Throwable и его подклассов Error и Exception из пакета java.lang.
Исключительные ситуации типа Error возникают только во время вы- полнения программы. Такие исключения связаны с серьезными ошибками, к примеру – переполнение стека, и не подлежат исправлению и не могут об- рабатываться приложением.
Во время выполнения могут генерироваться также исключения, которые могут быть обработаны без ущерба для выполнения программы.
Обычно используется один из трех способов обработки исключений: перехват и обработка исключения в блоке try-catch метода; объявление исключения в секции throws метода и передача вызыва- ющему методу (для проверяемых исключений); использование собственных исключений.
В программировании часто возникают ситуации, когда программисту необ- ходимо самому инициировать генерацию исключения для указания, например, на заведомо ошибочный результат выполнения операции, на некорректные значения параметра метода и др. Исключительную ситуацию можно создать с помощью оператора throw, если объект-исключение уже существует, или инициализиро- вать его прямо после этого оператора. Оператор throw используется для генера- ции исключения. Для этого может быть использован объект класса Throwable или объект его подкласса, а также ссылки на них. Общая форма записи инструк- ции throw, генерирующей исключение: throw объектThrowable;
При достижении оператора throw выполнение кода прекращается. Ближай- ший блок try проверяется на наличие соответствующего обработчика catch. Если он существует, управление передается ему, иначе проверяется следующий из вложенных операторов try. Инициализация объекта-исключения без операто- ра throw никакой исключительной ситуации не вызовет
Возможна ситуация, при которой нужно выполнить некоторые действия по завершению программы (закрыть поток, освободить соединение с базой данных) вне зависимости от того, произошло исключение или нет. В этом случае исполь- зуется блок finally, который выполняется после инструкций try или catch
Каждому разделу try должен соответствовать по крайней мере один раздел catch или блок finally. Блок finally часто используется для закрытия файлов и освобождения других ресурсов, захваченных для временного использо- вания в начале выполнения метода. Код блока выполняется перед выходом из метода даже в том случае, если перед ним были выполнены инструкции вида re- turn, break, continue.
23. Собственные исключения. Наследование и исключения. Отладочный механизм assertion.
Разработчик может создать собственное исключение как подкласс класса Exception и затем использовать его при обработке ситуаций, не являющихся исключениями с точки зрения языка, но нарушающих логику вещей.
Борьба за качество программ ведется всеми возможными способами. На этапе отладки найти неявные ошибки в функционировании приложения бывает доволь- но сложно. Например, в методе, устанавливающем возраст пользователя, инфор- мация о возрасте извлекается из внешних источников (файл, БД), и в результате получается отрицательное значение. Далее неверные данные влияют на результат вычисления среднего возраста пользователей и т.д. Определять и исправлять та- кие ситуации позволяет механизм проверочных утверждений (assertion). При по- мощи этого механизма можно сформулировать требования к входным, выходным и промежуточным данным методов классов в виде некоторых логических условий. Попытка обработать ситуацию появления отрицательного возраста может вы- глядеть следующим образом: int age = ob.getAge(); if (age >= 0) { // реализация } else { // сообщение о неправильных данных } Теперь механизм assertion позволяет создать код, который будет генерировать исключение на этапе отладки проверки постусловия или промежуточных данных в виде: int age = ob.getAge(); assert (age >= 0): "NEGATIVE AGE!!!"; // реализация
Правописание инструкции assert: assert (boolexp): expression; assert (boolexp); Выражение boolexp может принимать только значение типов boolean или Boolean, а expression – любое значение, которое может быть преобра- зовано к строке. Если логическое выражение получает значение false, то гене- рируется исключение AssertionError, и выполнение программы прекращает- ся с выводом на консоль значения выражения expression (если оно задано).
24. Класс File. Байтовые и символьные потоки ввода/вывода. Предопределенные потоки.
Для работы с физическим файлами и каталогами (директориями), располо- женными на внешних носителях, в приложениях Java используются классы из пакета java.io. Класс File служит для хранения и обработки в качестве объектов каталогов и имен файлов. Этот класс не содержит методы для работы с содержимым файла, но позволяет манипулировать такими свойствами файла, как права доступа, дата и время создания, путь в иерархии каталогов, создание, удаление файла, изменение его имени и каталога и т.д.
При создании объекта класса File любым из конструкторов компилятор не выполняет проверку на существование физического файла с заданным путем. Существует разница между разделителями, употребляющимися при записи пути к файлу: для системы Unix – “/”, а для Windows – “\\”. Для случаев, когда неизвестно, в какой системе будет выполняться код, предусмотрены специальные поля в классе File: public static final String separator; public static final char separatorChar; С помощью этих полей можно задать путь, универсальный в любой системе: File myFile = new File(File.separator + ”com” + File.separator + ”myfile.txt” ); Также предусмотрен еще один тип разделителей – для директорий: public static final String pathSeparator; public static final char pathSeparatorChar; К примеру, для ОС Unix значение pathSeparator=”;”, а для Windows – pathSeparator=”:”.
При создании приложений всегда возникает необходимость прочитать инфор- мацию из какого-либо источника и сохранить результат. Действия по чтению/за- писи информации представляют собой стандартный и простой вид деятельности. Самые первые классы ввода/вывода связаны с передачей и извлечением последо- вательности байтов. Потоки ввода последовательности байтов являются подклассами абстракт- ного класса InputStream, потоки вывода подклассами абстрактного класса OutputStream. Эти классы являются суперклассами для ввода массивов бай- тов, строк, объектов, а также для выбора из файлов и сетевых соединений. При работе с файлами используются подклассы этих классов соответственно FileInputStream и FileOutputStream, конструкторы которых открыва- ют поток и связывают его с соответствующим физическим файлом.
Для чтения байта или массива байтов используются абстрактные методы read() и read(byte[] b) класса InputStream. Метод возвращает -1, если достигнут конец потока данных, поэтому возвращаемое значение имеет тип int, не byte. При взаимодействии с информационными потоками возмож- ны различные исключительные ситуации, поэтому обработка исключений вида try-catch при использовании методов чтения и записи является обязатель- ной. В конкретных классах потоков ввода указанные выше методы реализованы в соответствии с предназначением класса. В классе FileInputStream данный метод читает один байт из файла, а поток System.in как встроенный объект подкласса InputStream позволяет вводить информацию с консоли. Абстракт- ный метод write(int b) класса OutputStream записывает один байт в поток вывода. Оба эти метода блокируют поток до тех пор, пока байт не будет записан или прочитан. После окончания чтения или записи в поток его всегда следует закрывать с помощью метода close(), для того чтобы освободить ре- сурсы приложения.
В отличие от классов FileInputStream и FileOutputStream класс RandomAccessFile позволяет осуществлять произвольный доступ к потокам как ввода, так и вывода. Поток рассматривается при этом как массив байтов, до- ступ к элементам осуществляется с помощью метода seek(long poz). Для создания потока можно использовать один из конструкторов: RandomAccessFile(String name, String mode); RandomAccessFile(File file, String mode);
Система ввода/вывода языка Java содержит стандартные потоки ввода, выво- да и вывода ошибок. Класс System пакета java.lang содержит поле in, ко- торое является ссылкой на объект класса InputStream, и поля out, err – ссылки на объекты класса PrintStream, объявленные со спецификаторами public static и являющиеся стандартными потоками ввода, вывода и вы- вода ошибок соответственно. Эти потоки связаны с консолью, но могут быть переназначены на другое устройство.
25. Класс Scanner.
Объект класса java.util.Scanner принимает форматированный объект (ввод) и преобразует его в двоичное представление. При вводе могут использо- ваться данные из консоли, файла, строки или любого другого источника, реали- зующего интерфейсы Readable или ReadableByteChannel. Класс определяет следующие конструкторы: Scanner(File source) throws FileNotFoundException Scanner(File source, String charset) throws FileNotFoundException Scanner(InputStream source) Scanner(InputStream source, String charset) Scanner(Readable source) Scanner(ReadableByteChannel source) Scanner(ReadableByteChannel source, String charset) Scanner(String source), где source – источник входных данных, а charset – кодировка. Объект класса Scanner читает лексемы из источника, указанного в кон- структоре, например из строки или файла. Лексема – это набор данных, выделен- ный набором разделителей (по умолчанию пробелами). В случае ввода из консо- ли следует определить объект: Scanner con = new Scanner(System.in); После создания объекта его используют для ввода, например целых чисел, следующим образом: write(con.hasNextInt()) { int n = con.nextInt(); }
Объект класса Scanner определяет границы лексемы, основываясь на набо- ре разделителей. Можно задавать разделители с помощью метода useDelimiter(Pattern pattern) или useDelimiter(String pattern), где pattern содержит набор разделителей.
26. Коллекции. Общие определения.
Коллекции – это хранилища, поддерживающие различные способы накопле- ния и упорядочения объектов с целью обеспечения возможностей эффективного доступа к ним. Они представляют собой реализацию абстрактных типов (структур) данных, поддерживающих три основные операции: добавление нового элемента в коллекцию; удаление элемента из коллекции; изменение элемента в коллекции. В качестве других операций могут быть реализованы следующие: просмот- реть элементы, подсчитать их количество и др. Применение коллекций обусловливается возросшими объемами обрабатыва- емой информации. Когда счет используемых объектов идет на сотни тысяч, мас- сивы не обеспечивают ни должной скорости, ни экономии ресурсов.
Коллекции в языке Java объединены в библиотеке классов java.util и представляют собой контейнеры для хранения и манипулирования объектами. До появления Java 2 эта библиотека содержала классы только для работы с про- стейшими структурами данных: Vector, Stack, Hashtable, BitSet, а также интерфейс Enumeration для работы с элементами этих классов. Коллекции, появившиеся в Java 2, представляют общую технологию хранения и доступа к объектам. Скорость обработки коллекций повысилась по сравнению с предыду- щей версией языка за счет отказа от их потокобезопасности. Поэтому если объект коллекции может быть доступен из различных потоков, что наиболее естественно для распределенных приложений, следует использовать коллекции из Java 1. Так как в коллекциях при практическом программировании хранится набор ссылок на объекты одного типа, следует обезопасить коллекцию от появления ссылок на другие не разрешенные логикой приложения типы. Такие ошибки при использовании нетипизированных коллекций выявляются на стадии выполнения, что повышает трудозатраты на исправление и верификацию кода. Поэтому начи- ная с версии 5.0 коллекции стали типизированными.
Интерфейсы коллекций: Map<K,V> – карта отображения вида “ключ-значение”; Collection<E> – вершина иерархии остальных коллекций; List<E> – специализирует коллекции для обработки списков; Set<E> – специализирует коллекции для обработки множеств, содержащих уникальные элементы. Все классы коллекций реализуют также интерфейсы Serializable, Cloneable (кроме WeakHashMap). Кроме того, классы, реализующие интер- фейсы List<E> и Set<E>, реализуют также интерфейс Iterable<E>. В интерфейсе Collection<E> определены методы, которые работают на всех коллекциях: boolean add(E obj) – добавляет obj к вызывающей коллекции и воз- вращает true, если объект добавлен, и false, если obj уже элемент коллекции; boolean addAll(Collection<? extends E> c) – добавляет все элементы коллекции к вызывающей коллекции; void clear() – удаляет все элементы из коллекции; boolean contains(Object obj) – возвращает true, если вызывающая коллекция содержит элемент obj; boolean equals(Object obj) – возвращает true, если коллекции эк- вивалентны; boolean isEmpty() – возвращает true, если коллекция пуста; Iterator<E> iterator() – извлекает итератор; boolean remove(Object obj) – удаляет obj из коллекции; int size() – возвращает количество элементов в коллекции; Object[] toArray() – копирует элементы коллекции в массив объектов; <T> T[] toArray(T a[]) – копирует элементы коллекции в массив объ- ектов определенного типа. Для работы с элементами коллекции применяются следующие интерфейсы: Comparator<T> – для сравнения объектов; Iterator<E>, ListIterator<E>, Map.Entry<K,V> – для перечисления и доступа к объектам коллекции.
Интерфейс Iterator<E> используется для построения объектов, которые обеспечивают доступ к элементам коллекции. К этому типу относится объект, возвращаемый методом iterator(). Такой объект позволяет просматривать
содержимое коллекции последовательно, элемента за элементом. Позиции итера- тора располагаются в коллекции между элементами. В коллекции, состоящей из N элементов, существует N+1 позиций итератора. Методы интерфейса Iterator<E>: boolean hasNext() – проверяет наличие следующего элемента, а в случае его отсутствия (завершения коллекции) возвращает false. Итератор при этом остается неизменным; E next() – возвращает объект, на который указывает итератор, и пере- двигает текущий указатель на следующий, предоставляя доступ к следующему элементу. Если следующий элемент коллекции отсутствует, то метод next() генерирует исключение NoSuchElementException; void remove() – удаляет объект, возвращенный последним вызовом ме- тода next(). Интерфейс ListIterator<E> расширяет интерфейс Iterator<E> и предназначен в основном для работы со списками. Наличие методов E previous(), int previousIndex() и boolean hasPrevious() обеспе- чивает обратную навигацию по списку. Метод int nextIndex() возвращает номер следующего итератора. Метод void add(E obj) позволяет вставлять элемент в список текущей позиции. Вызов метода void set(E obj) произво- дит замену текущего элемента списка на объект, передаваемый методу в качестве параметра. Интерфейс Map.Entry предназначен для извлечения ключей и значений карты с помощью методов K getKey() и V getValue() соответственно. Вы- зов метода V setValue(V value) заменяет значение, ассоциированное с те- кущим ключом.
27. Списки.
Класс ArrayList<E> – динамический массив объектных ссылок. Расширяет класс AbstractList<E> и реализует интерфейс List<E>. Класс имеет кон- структоры: ArrayList() ArrayList(Collection <? extends E> c) ArrayList(int capacity) Практически все методы класса являются реализацией абстрактных методов из суперклассов и интерфейсов. Методы интерфейса List<E> позволяют встав- лять и удалять элементы из позиций, указываемых через отсчитываемый от нуля индекс: void add(int index, E element) – вставляет element в позицию, указанную в index; void addAll(int index, Collection<? extends E> c) – встав- ляет в вызывающий список все элементы коллекции с, начиная с позиции index; E get(int index) – возвращает элемент в виде объекта из позиции index; int indexOf(Object ob) – возвращает индекс указанного объекта; E remove(int index) – удаляет объект из позиции index; E set(int index, E element) – заменяет объект в позиции index, возвращает при этом удаляемый элемент; List<E> subList(int fromIndex, int toIndex) – извлекает часть коллекции в указанных границах. Удаление и добавление элементов для такой коллекции представляет собой ресурсоемкую задачу, поэтому объект ArrayList<E> лучше всего подходит для хранения неизменяемых списков.
Коллекция LinkedList<E> реализует связанный список. В отличие от мас- сива, который хранит объекты в последовательных ячейках памяти, связанный список хранит объекты отдельно, но вместе со ссылками на следующее и преды- дущее звенья последовательности. В добавление ко всем имеющимся методам в LinkedList<E> реализованы методы void addFirst(E ob), void addLast(E ob), E getFirst(), E getLast(), E removeFirst(), E removeLast() добавляющие, извле- кающие, удаляющие и извлекающие первый и последний элементы списка соот- ветственно. Класс LinkedList<E> реализует интерфейс Queue<E>, что позволяет предположить, что такому списку легко придать свойства очереди. К тому же специализированные методы интерфейса Queue<E> по манипуляции первым и
последним элементами такого списка E element(), boolean offer(E o), E peek(), E poll(), E remove() работают немного быстрее, чем соответ- ствующие методы класса LinkedList<E>. Методы интерфейса Queue<E>: E element() – возвращает, но не удаляет головной элемент очереди; boolean offer(E o) – вставляет элемент в очередь, если возможно; E peek() – возвращает, но не удаляет головной элемент очереди, возвра- щает null, если очередь пуста; E poll() – возвращает и удаляет головной элемент очереди, возвращает null, если очередь пуста; E remove() – возвращает и удаляет головной элемент очереди. Методы element() и remove() отличаются от методов peek() и poll() тем, что генерируют исключение, если очередь пуста.
28. Множества.
Интерфейс Set<E> объявляет поведение коллекции, не допускающей дуб- лирования элементов. Интерфейс SortedSet<E> наследует Set<E> и объявля- ет поведение набора, отсортированного в возрастающем порядке, заранее опреде- ленном для класса. Интерфейс NavigableSet существенно облегчает поиск элементов.
Класс HashSet<E> наследуется от абстрактного суперкласса AbstractSet<E> и реализует интерфейс Set<E>, используя хэш-таблицу для хранения коллекции. Ключ (хэш-код) используется вместо индекса для доступа к данным, что значительно ускоряет поиск определенного элемента. Скорость по- иска существенна для коллекций с большим количеством элементов. Все элемен- ты такого множества упорядочены посредством хэш-таблицы, в которой хранятся хэш-коды элементов
Класс TreeSet<E> для хранения объектов использует бинарное дерево. При добавлении объекта в дерево он сразу же размещается в необходимую позицию с уче- том сортировки. Сортировка происходит благодаря тому, что все добавляемые эле- менты реализуют интерфейсы Comparator и Comparable. Обработка операций удаления и вставки объектов происходит медленнее, чем в хэш-множествах, но быстрее, чем в списках.
Абстрактный класс EnumSet<E extends Enum<E>> наследуется от аб- страктного класса AbstractSet. Специально реализован для работы с типами enum. Все элементы такой коллекции должны принадлежать единственному типу enum, определенному явно или неявно. Внутренне множество представимо в виде вектора битов, обычно единственного long. Множества нумераторов поддержи- вают перебор по диапазону из нумераторов. Скорость выполнения операций над таким множеством очень высока, даже если в ней участвует большое количество элементов
29. Карты отображений.
Карта отображений – это объект, который хранит пару “ключ-значение”. По- иск объекта (значения) облегчается по сравнению с множествами за счет того, что его можно найти по его уникальному ключу. Уникальность объектов-ключей должна обеспечиваться переопределением методов hashCode() и equals() пользовательским классом. Если элемент с указанным ключом отсутствует в кар- те, то возвращается значение null. Классы карт отображений: AbstractMap<K,V> – реализует интерфейс Map<K,V>; HashMap<K,V> – расширяет AbstractMap<K,V>, используя хэш-таблицу, в которой ключи отсортированы относительно значений их хэш-кодов; TreeMap<K,V> – расширяет AbstractMap<K,V>, используя дерево, где ключи расположены в виде дерева поиска в строгом порядке. WeakHashMap<K,V> позволяет механизму сборки мусора удалять из карты значения по ключу, ссылка на который вышла из области видимости приложения. LinkedHashMap<K,V> запоминает порядок добавления объектов в карту и образует при этом дважды связанный список ключей. Этот механизм эффективен, только если превышен коэффициент загруженности карты при работе с кэш- памятью и др.
Для класса IdentityHashMap<K,V> хэш-коды объектов-ключей вычис- ляются методом System.iden
Дата добавления: 2015-01-10; просмотров: 1868;