Java.lang.String Java SE 6

Java.lang.Integer 71

В рассмотренном примере были созданы объекты типаOptional: ob1 на основе типа Integer и ob2 на основе типа String при помощи различных конструкторов. При компиляции вся информация о generic-типах стирается и заменяется для членов класса и методов заданными типами или типом Object, если параметр не задан, как для объекта ob3. Такая реализация необходима для обеспечения совместимости с кодом, созданным в предыдущих версиях языка.

Объявление generic-типа в виде <T>, несмотря на возможность использовать любой тип в качестве параметра, ограничивает область применения разрабатываемого класса. Переменные такого типа могут вызывать только методы класса Object. Доступ к другим методам ограничивает компилятор, предупреждая возможные варианты возникновения ошибок.

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

public class OptionalExt <T extends Tип> {

Private T value;

}

Такая запись говорит о том, что в качестве типа Т разрешено применять только классы, являющиеся наследниками (суперклассами) класса Tип, и соответственно появляется возможность вызова методов ограничивающих (bound) типов.

Часто возникает необходимость в метод параметризованного класса одного допустимого типа передать объект этого же класса, но параметризованного другим типом. В этом случае при определении метода следует применить метасимвол ?. Метасимвол также может использоваться с ограничением extends для передаваемого типа.

/*пример # 11 : использование метасимвола в параметризованном классе: Mark.java, Runner.java */

package chapt03;

 

public class Mark<T extends Number> {

public T mark;

 

public Mark(T value) {

mark = value;

}

public T getMark() {

return mark;

}

public int roundMark() {

return Math.round(mark.floatValue());

}

/* вместо */ // public boolean sameAny(Mark<T> ob) {

public boolean sameAny(Mark<?> ob) {

return roundMark() == ob.roundMark();

}

public boolean same(Mark<T> ob) {

return getMark() == ob.getMark();

}

}

package chapt03;

 

public class Runner {

public static void main(String[] args) {

// Mark<String> ms = new Mark<String>(“7”); //ошибка компиляции

Mark<Double> md = new Mark<Double>(71.4D);//71.5d

System.out.println(md.sameAny(md));

Mark<Integer> mi = new Mark<Integer>(71);

System.out.println(md.sameAny(mi));

// md.same(mi); //ошибка компиляции

System.out.println(md.roundMark());

}

}

В результате будет выведено:

True

True

Метод sameAny(Mark<?> ob) может принимать объекты типа Mark, инициализированные любым из допустимых для этого класса типов, в то время как метод с параметром Mark<T>мог бы принимать объекты с инициализацией того же типа, что и вызывающий метод объект.

Для generic-типов существует целый ряд ограничений. Например, невозмож­но выполнить явный вызов конструктора generic-типа:

classOptional <T> {

T value = new T();

}

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

По аналогичным причинам generic-поля не могут быть статическими, статические методы не могут иметь generic-параметры или обращаться к generic-полям, например:

/*пример # 12 : неправильное объявление полей параметризованного класса: Failed.java */

package chapt03;

class Failed <T1, T2> {

static T1 value;

T2 id;

 

static T1 getValue() {

return value;

}

static void use() {

System.out.print(id);

}

}

Параметризованные методы

Параметризованный (generic) метод определяет базовый набор операций, которые будут применяться к разным типам данных, получаемых методом в качестве параметра, и может быть записан, например, в виде:

<T extends Тип> returnType methodName(T arg) {}

<T> returnType methodName(T arg) {}

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

Generic-методы могут находиться как в параметризованных классах, так и в обычных. Параметр метода может не иметь никакого отношения к параметру своего класса. Метасимволы применимы и к generic-методам.

/* пример # 13 : параметризованный метод: GenericMethod.java */

public class GenericMethod {

public static <T extends Number> byte asByte(T num) {

long n = num.longValue();

if (n >= -128 && n <= 127) return (byte)n;

else return 0;

}

public static void main(String [] args) {

System.out.println(asByte(7));

System.out.println(asByte(new Float("7.f")));

// System.out.println(asByte(new Character('7'))); // ошибка компиляции

}

}

Объекты типа Integer (int будет в него упакован) и Float являются подклассами абстрактного класса Number, поэтому компиляция проходит без затруднений. Класс Character не обладает вышеуказанным свойством, и его объект не может передаваться в метод asByte(T num).

Методы с переменным числом параметров

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

/* пример # 14: определение количества параметров метода: DemoVarargs.java */

package chapt03;

 

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

В примере приведен простейший метод с переменным числом параметров. Метод getArgCount() выводит все переданные ему аргументы и возвращает их количество. При передаче параметров в метод из них автоматически создается массив. Второй вызов метода в примере позволяет передать в метод массив. Метод может быть вызван и без аргументов.

Чтобы передать несколько массивов в метод по ссылке, следует использовать следующее объявление:

void methodName(Тип[]... args){}

Методы с переменным числом аргументов могут быть перегружены:

void methodName(Integer...args) {}

void methodName(int x1, int x2) {}

void methodName(String...args) {}

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

/* пример # 15 : передача массивов: DemoOverload.java */

package chapt03;

 

public class DemoOverload {

public static void printArgCount(Object... args) {//1

System.out.println("Object args: " + args.length);

}

public static void printArgCount(Integer[]...args){//2

System.out.println("Integer[] args: " + args.length);

}

public static void printArgCount(int... args) {//3

System.out.print("int args: " + +args.length);

}

public static void main(String[] args) {

Integer[] i = { 1, 2, 3, 4, 5 };

 

printArgCount(7, "No", true, null);

printArgCount(i, i, i);

printArgCount(i, 4, 71);

printArgCount(i);//будет вызван метод 1

printArgCount(5, 7);

// printArgCount();//неопределенность!

}

}

В результате будет выведено:

Object args: 4

Integer[] args: 3

Object args: 3

Object args: 5

int args: 2

При передаче в метод printArgCount()единичного массива i компи­лятор отдает предпочтение методу с параметром Object... args, так как имя массива является объектной ссылкой и потому указанный параметр будет ближайшим. Метод с параметром Integer[]...args не вызывается, так как ближайшей объектной ссылкой для него будет Object[]...args. Метод с параметром Integer[]...args будет вызван для единичного массива только в случае отсутствия метода с параметром Object...args.

При вызове метода без параметров возникает неопределенность из-за невозможности однозначного выбора.

Не существует также ограничений и на переопределение подобных методов.

Единственным ограничением является то, что параметр вида
Тип...args должен быть последним в объявлении метода, например:

void methodName(Тип1 obj, Тип2... args) {}

Перечисления

Типобезопасные перечисления (typesafe enums) в Java представляют собой классы и являются подклассами абстрактного класса java.lang.Enum. При этом объекты перечисления инициализируются прямым объявлением без помощи оператора new. При инициализации хотя бы одного перечисления происходит инициализация всех без исключения оставшихся элементов данного перечисления.

В качестве простейшего применения перечисления можно рассмотреть следующий код:

/* пример # 16 : применение перечисления: SimpleUseEnum.java */

packagechapt02;

enum Faculty {

MMF, FPMI, GEO

}

public class SimpleUseEnum {

public static void main(String args[]) {

Faculty current;

current = Faculty.GEO;

switch (current) {

case GEO:

System.out.print(current);

break;

case MMF:

System.out.print(current);

break;

// case LAW : System.out.print(current);//ошибка компиляции!

default:

System.out.print("вне case: " + current);

}

}

}

В операторах case используются константы без уточнения типа перечисле­ния, так как его тип определен в switch.

Перечисление как подкласс класса Enum может содержать поля, конструкто­ры и методы, реализовывать интерфейсы. Каждый тип enumможет использо­вать методы:

static enumType[] values()– возвращает массив, содержащий все элементы перечисления в порядке их объявления;

static T valueOf(Class<T> enumType, String arg)– возвра­щает элемент перечисления, соответствующий передаваемому типу и значению передаваемой строки;

static enumType valueOf(String arg)– возвращает элемент пере­числения, соответствующий значению передаваемой строки;

int ordinal()– возвращает позицию элемента перечисления.

/* пример # 17 : объявление перечисления с методом : Shape.java */

packagechapt02;

 

enum Shape {

RECTANGLE, TRIANGLE, CIRCLE;

public double square(double x, double y) {

switch (this) {

case RECTANGLE:

return x * y;

case TRIANGLE:

return x * y / 2;

case CIRCLE:

return Math.pow(x, 2) * Math.PI;

}

throw new EnumConstantNotPresentException(

this.getDeclaringClass(),this.name());

}

}

/* пример # 18 : применение перечисления: Runner.java */

packagechapt02;

 

public class Runner {

public static void main(String args[]) {

double x = 2, y = 3;

Shape[] arr = Shape.values();

for (Shape sh : arr)

System.out.printf("%10s = %5.2f%n",

sh, sh.square(x, y));

}

}

В результате будет выведено:

RECTANGLE = 6,00

TRIANGLE = 3,00

CIRCLE = 12,57

Каждый из элементов перечисления в данном случае представляет собой в том числе и арифметическую операцию, ассоциированную с методом square(). Без throwданный код не будет компилироваться, так как компилятор не исключает появления неизвестного элемента. Данная инструкция позволяет указать на возможную ошибку при появлении необъявленной фигуры. Поэтому и при добавлении нового элемента необходимо добавлять соответствующий ему case.

/* пример # 19 : конструкторы и члены перечисления: DeanDemo.java */

packagechapt02;

enumDean {

MMF("Бендер"), FPMI("Балаганов"), GEO("Козлевич");

String name;

 

Dean(String arg) {

name = arg;

}

String getName() {

returnname;

}

}

packagechapt02;

public classDeanDemo {

public static voidmain(String[] args) {

Dean dn = Dean.valueOf("FPMI");

System.out.print(dn.ordinal());

System.out.println(" : " + dn + " : " + dn.getName());

}

}

В результате будет выведено:

1 : FPMI : Балаганов

Однако на перечисления накладывается целый ряд ограничений.

Им запрещено:

Ÿ быть суперклассами;

Ÿ быть подклассами;

Ÿ быть абстрактными;

Ÿ создавать экземпляры, используя ключевое слово new.

Аннотации

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

В следующем коде приведено объявление аннотации.

/* пример # 20 : многочленная аннотация : RequestForCustomer.java */

package chapt03;

 

public @interface RequestForCustomer {

int level();

String description();

String date();

}

Ключевому слову interface предшествует символ @. Такая запись сообщает компилятору об объявлении аннотации. В объявлении также есть три метода-члена: int level(), String description(), String date().

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

Все типы аннотаций автоматически расширяют интерфейс java.lang.annotation.Annotation. В этом интерфейсе даны методы: hashCode(), equals() и toString(), определенные в типе Object. В нем также приведен метод annotationType(), который возвращает объект типа Сlass, представляющий вызывающую аннотацию.

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

Применяя аннотацию, нужно задавать значения для ее методов-членов. Далее приведен фрагмент, в котором аннотация RequestForCustomer сопровождает объявление метода:

@RequestForCustomer (

level = 2,

description = "Enable time",

date = "10/10/2007"

)

public voidcustomerThroughTime() {

//...

}

Данная аннотация связана с методом customerThroughTime(). За именем аннотации, начинающимся с символа @, следует заключенный в круглые скобки список инициализирующих значений для методов-членов. Для того чтобы передать значение методу-члену, имени этого метода присваивается значение. Таким образом, в приведенном фрагменте строка "Enable time" присваивается методу description(), члену аннотации типа RequestForCustomer. При этом в присваивании после имени description нет круглых скобок. Когда методу-члену передается инициализирующее значение, используется только имя метода. Следовательно, в данном контексте методы-члены выглядят как поля.

/* пример # 21 : применение аннотации: Request.java */

package chapt03;

import java.lang.reflect.Method;

 

public class Request {

@RequestForCustomer(level = 2,

description = "Enable time",

date = "10/10/2007")

public void customerThroughTime() {

try {

Class c = this.getClass();

Method m = c.getMethod("customerThroughTime");

RequestForCustomer ann =

m.getAnnotation(RequestForCustomer.class);

//запрос аннотаций

System.out.println(ann.level() + " "

+ ann.description() + " "

+ ann.date());

} catch (NoSuchMethodException e) {

System.out.println("метод не найден");

}

}

public static void main(String[] args) {

Request ob = new Request();

ob.customerThroughTime();

}

}

В результате будет выведено:

2 Enable time 10/10/2007

Если аннотация объявляется в отдельном файле, то ей нужно задать правило сохранения RUNTIME в виде кода

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME) //правило сохранения

помещаемого перед объявлением аннотации, которое предоставляет максимальную продолжительность существования аннотации.

С правилом SOURCE аннотация существует только в исходном тексте программы и отбрасывается во время компиляции.

Аннотация с правилом сохранения CLASS помещается в процессе компиляции в файл .class, но не доступна в JVM во время выполнения.

Аннотация, заданная с правилом сохранения RUNTIME, помещается в файл .class в процессе компиляции и доступна в JVM во время выполнения. Следовательно, правило RUNTIME предлагает максимальную продолжительность существования аннотации.

Основные типы аннотаций: аннотация-маркер, одночленная и многочленная.

Аннотация-маркер не содержит методов-членов. Цель – пометить объявление. В этом случае достаточно присутствия аннотации. Поскольку у интерфейса аннотации-маркера нет методов-членов, достаточно определить наличие аннотации.

public @interface TigerAnnotation {}

Для проверки наличия аннотации-маркера используется метод isAnnotationPresent().

Одночленная аннотация содержит единственный метод-член. Для этого типа аннотации допускается краткая условная форма задания значения для метода-члена. Если есть только один метод-член, то просто указывается его значение при создании аннотации. Имя метода-члена указывать не нужно. Но для того чтобы воспользоваться краткой формой, следует для метода-члена использовать имя value().

Многочленные аннотации содержат несколько методов-членов. Поэтому используется полный синтаксис (имя_параметра = значение) для каждого параметра.

В языке Java определено семь типов встроенных аннотаций, четыре типа – @Retention, @Documented, @Target и @Inherited – импортируются из пакета java.lang.annotation. Оставшиеся три – @Override, @Deprecated и @Suppresswarnings – из пакета java.lang.

Аннотации получают все более широкое распространение и активно используются в различных технологиях.

Задания к главе 3

Вариант A

1. Определить класс Вектор размерности n. Реализовать методы сложения, вычитания, умножения, инкремента, декремента, индексирования. Определить массив из m объектов. Каждую из пар векторов передать в методы, возвращающие их скалярное произведение и длины. Вычислить и вывести углы между векторами.

2. Определить класс Вектор размерности n. Определить несколько конструкторов. Реализовать методы для вычисления модуля вектора, скалярного произведения, сложения, вычитания, умножения на константу. Объявить массив объектов. Написать метод, который для заданной пары векторов будет определять, являются ли они коллинеарными или ортогональными.

3. Определить класс Вектор в R3. Реализовать методы для проверки векторов на ортогональность, проверки пересечения неортогональных векторов, сравнения векторов. Создать массив из m объектов. Определить, какие из векторов компланарны.

4. Определить класс Матрица размерности (n x n). Класс должен содержать несколько конструкторов. Реализовать методы для сложения, вычитания, умножения матриц. Объявить массив объектов. Создать методы, вычисляющие первую и вторую нормы матрицы . Определить, какая из матриц имеет наименьшую первую и вторую нормы.

5. Определить класс Матрица размерности (m x n). Класс должен содержать несколько конструкторов. Объявить массив объектов. Передать объекты в метод, меняющий местами строки с максимальным и минимальным элементами k-го столбца. Создать метод, который изменяет i-ю матрицу путем возведения ее в квадрат.

6. Определить класс Цепная дробь Определить методы сложения, вычитания, умножения, деления. Вычислить значение для заданного n, x, a[n].

7. Определить класс Дробь в виде пары (m,n). Класс должен содержать несколько конструкторов. Реализовать методы для сложения, вычи­тания, умножения и деления дробей. Объявить массив из k дробей, ввести/вы­вести значения для массива дробей. Создать массив объектов и передать его в метод, который изменяет каждый элемент массива с четным индексом путем добавления следующего за ним элемента массива.

8. Определить класс Комплекс. Класс должен содержать несколько конструкторов. Реализовать методы для сложения, вычитания, умножения, деления, присваивания комплексных чисел. Создать два вектора размерности n из комплексных координат. Передать их в метод, который выполнит их сложение.

9. Определить класс Квадратное уравнение. Класс должен содержать несколько конструкторов. Реализовать методы для поиска корней, экстремумов, а также интервалов убывания/возрастания. Создать масссив объектов и определить наибольшие и наименьшие по значению корни.

10. Определить класс Булева матрица (BoolMatrix)размерности (n x m). Класс должен содержать несколько конструкторов. Реализовать методы для логического сложения (дизъюнкции), умножения и инверсии матриц. Реализовать методы для подсчета числа единиц в матрице и упорядочения строк в лексикографическом порядке.

11. Построить класс Булев вектор (BoolVector) размерности n. Определить несколько конструкторов. Реализовать методы для выполнения поразрядных конъюнкции, дизъюнкции и отрицания векторов, а также подсчета числа единиц и нулей в векторе.

12. Определить класс Множество символов мощности n. Написать несколько конструкторов. Реализовать методы для определения принадлежности заданного элемента множеству; пересечения, объединения, разности двух множеств. Создать методы сложения, вычитания, умножения (пересечения), индексирования, присваивания. Создать массив объектов и передавать пары объектов в метод другого класса, который строит множество, состоящее из элементов, входящих только в одно из заданных множеств.

13. Определить класс Полином степени n. Создать методы для сложения и умножения объектов. Объявить массив из m полиномов и передать его в метод, вычисляющий сумму полиномов массива. Определить класс Рациональный полином с полем типа Полином. Определить метод для сложения: и методы для ввода/вывода.

14. Определить класс Нелинейное уравнениедля двух переменных. Написать несколько конструкторов. Создать методы для сложения и умножения объектов. Реализовать метод определения корней методом биекции.

15. Определить класс Определённый интегралс аналитически подынтегральной функцией. Написать несколько конструкторов. Создать методы для вычисления значения по формуле левых прямоугольников, по формуле правых прямоугольников, по формуле средних прямоугольников, по формуле трапеций, по формуле Симпсона (параболических трапеций).

16. Определить класс Массивс аналитически подынтегральной функцией. Написать несколько конструкторов. Создать методы сортировки: об­менная сортировка (метод пузырька); обменная сортировка «Шейкер-сортировка», сортировка посредством выбора (метод простого выбора), сортировка вставками: метод хеширования (сортировка с вычислением адреса), сортировка вставками (метод простых вставок), сортировка би­нарного слияния, сортировка Шелла (сортировка с убывающим шагом).

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

Вариант B

Создать классы, спецификации которых приведены ниже. Определить конструкторы и методы setТип(), getТип(),toString(). Определить дополнительно методы в классе, создающем массив объектов. Задать критерий выбора данных и вывести эти данные на консоль.

1. Student: id, Фамилия, Имя, Отчество, Дата рождения, Адрес, Телефон, Факультет, Курс, Группа.

Создать массив объектов. Вывести:

a) список студентов заданного факультета;

b) списки студентов для каждого факультета и курса;

c) список студентов, родившихся после заданного года;

d) список учебной группы.

2. Customer: id, Фамилия, Имя, Отчество, Адрес, Номер кредитной карточки, Номер банковского счета.

Создать массив объектов. Вывести:

a) список покупателей в алфавитном порядке;

b) список покупателей, у которых номер кредитной карточки находится в заданном интервале.

3. Patient: id, Фамилия, Имя, Отчество, Адрес, Телефон, Номер медицинской карты, Диагноз.

Создать массив объектов. Вывести:

a) список пациентов, имеющих данный диагноз;

b) список пациентов, номер медицинской карты у которых находится в заданном интервале.

4. Abiturient: id, Фамилия, Имя, Отчество, Адрес, Телефон, Оценки.

Создать массив объектов. Вывести:

a) список абитуриентов, имеющих неудовлетворительные оценки;

b) список абитуриентов, средний балл у которых выше заданного;

c) выбрать заданное число n абитуриентов, имеющих самый высокий средний балл (вывести также полный список абитуриентов, имеющих полупроходной балл).

5. Book: id, Название, Автор(ы), Издательство, Год издания, Количество страниц, Цена, Переплет.

Создать массив объектов. Вывести:

a) список книг заданного автора;

b) список книг, выпущенных заданным издательством;

c) список книг, выпущенных после заданного года.

6. House: id, Номер квартиры, Площадь, Этаж, Количество комнат, Улица, Тип здания, Срок эксплуатации.

Создать массив объектов. Вывести:

a) список квартир, имеющих заданное число комнат;

b) список квартир, имеющих заданное число комнат и расположенных на этаже, который находится в заданном промежутке;

c) список квартир, имеющих площадь, превосходящую заданную.

7. Phone: id, Фамилия, Имя, Отчество, Адрес, Номер кредитной карточки, Дебет, Кредит, Время городских и междугородных разговоров.

Создать массив объектов. Вывести:

a) сведения об абонентах, у которых время внутригородских разговоров превышает заданное;

b) сведения об абонентах, которые пользовались междугородной связью;

c) сведения об абонентах в алфавитном порядке.

8. Car: id, Марка, Модель, Год выпуска, Цвет, Цена, Регистрационный номер.

Создать массив объектов. Вывести:

a) список автомобилей заданной марки;

b) список автомобилей заданной модели, которые эксплуатируются больше n лет;

c) список автомобилей заданного года выпуска, цена которых больше указанной.

9. Product: id, Наименование, UPC, Производитель, Цена, Срок хранения, Количество.

Создать массив объектов. Вывести:

a) список товаров для заданного наименования;

b) список товаров для заданного наименования, цена которых не превосходит заданную;

c) список товаров, срок хранения которых больше заданного.

10. Train: Пункт назначения, Номер поезда, Время отправления, Число мест (общих, купе, плацкарт, люкс).

Создать массив объектов. Вывести:

a) список поездов, следующих до заданного пункта назначения;

b) список поездов, следующих до заданного пункта назначения и отправляющихся после заданного часа;

c) список поездов, отправляющихся до заданного пункта назначения и имеющих общие места.

11. Bus: Фамилия и инициалы водителя, Номер автобуса, Номер маршрута, Марка, Год начала эксплуатации, Пробег.

Создать массив объектов. Вывести:

a) список автобусов для заданного номера маршрута;

b) список автобусов, которые эксплуатируются больше 10 лет;

c) список автобусов, пробег у которых больше 100000 км.

12. Airlines: Пункт назначения, Номер рейса, Тип самолета, Время вылета, Дни недели.

Создать массив объектов. Вывести:

a) список рейсов для заданного пункта назначения;

b) список рейсов для заданного дня недели;

c) список рейсов для заданного дня недели, время вылета для которых больше заданного.

Тестовые задания к главе 3

Вопрос 3.1.

Какие из ключевых слов могут быть использованы при объявлении конструктора?

1) private;

2) final;

3) native;

4) abstract;

5) protected.

Вопрос 3.2.

Как следует вызвать конструктор класса Quest3, чтобы в результате выполнения кода была выведена на консоль строка "Конструктор".

public class Quest3 {

Quest3 (int i){ System.out.print("Конструктор"); }

public static void main(String[] args){

Quest3 s= new Quest3();

//1

}

public Quest3() {

//2

}

{

//3

} }

1) вместо //1 написать Quest3(1);

2) вместо //2 написать Quest3(1);

3) вместо //3 написать newQuest3(1);

4) вместо //3 написать Quest3(1).

Вопрос 3.3.

Какие из следующих утверждений истинные?

1) nonstatic-метод не может быть вызван из статического метода;

2) static-метод не может быть вызван из нестатического метода;

3) private-метод не может быть вызван из другого метода этого класса;

4) final-метод не может быть статическим.

Вопрос 3.4.

Дан код:

public class Quest5 {

{System.out.print("1");}

static{System.out.print("2");}

Quest5(){System.out.print("3");}

public static void main(String[] args) {

System.out.print("4");

} }

В результате при компиляции и запуске будет выведено:

1) 1234;

2) 4;

3) 34;

4) 24;

5) 14.

 

 
Глава 4

НАСЛЕДОВАНИЕ И ПОЛИМОРФИЗМ

Наследование

Отношение между классами, при котором характеристики одного класса (суперкласса) передаются другому классу (подклассу) без их повторного описания, называется наследованием.

Подкласс наследует переменные и методы суперкласса, используя ключевое слово extends. Класс может также реализовывать любое число интерфейсов, используя ключевое слово – implements. Подкласс имеет прямой доступ ко всем открытым переменным и методам родительского класса, как будто они находятся в подклассе. Исключение составляют члены класса, помеченные
private (во всех случаях) и «по умолчанию» для подкласса в другом пакете.
В любом случае (даже если ключевое слово extends отсутствует) класс автоматически наследует свойства суперкласса всех классов – класса Object.

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

Подкласс дополняет члены базового класса своими переменными и методами, имена которых могут частично совпадать с именами членов суперкласса. Если имена методов совпадают, а параметры различаются, то такое явление называется перегрузкой методов.

В подклассе можно объявить (переопределить) метод с тем же именем, списком параметров и возвращаемым значением, что и у метода суперкласса.

Способность ссылки динамически определять версию переопределенного метода в зависимости от переданного ссылке в сообщении типа объекта называется полиморфизмом.

Полиморфизм является основой для реализации механизма динамического или «позднего связывания».

В следующем примере переопределяемый метод typeEmployee()находится в двух классах Employee и Manager. В соответствии с принципом полиморфизма вызывается метод, наиболее близкий к текущему объекту.

/* пример # 1 : наследование класса и переопределение метода:

Employee.java: Manager.java: Runner.java */

packagechapt04;

 

public class Employee {// рядовой сотрудник

private int id;

public Employee(int idc) {

super();/* по умолчанию, необязательный явный вызов

конструктора суперкласса */

id = idc;

}

public int getId() {

return id;

}

public void typeEmployee() {

// ...

System.out.println("Работник");

}

}

 

packagechapt04;

// сотрудник с проектом, за который он отвечает

 

public class Manager extends Employee {

private int idProject;

 

public Manager(int idc, int idp) {

super(idc); /* вызов конструктора суперкласса

с параметром */

idProject = idp;

}

public int getIdProject() {

return idProject;

}

public void typeEmployee() {

// ...

System.out.println("Менеджер");

}

}

packagechapt04;

 

public class Runner {

public static void main(String[] args) {

Employee b1 = new Employee(7110);

Employee b2 = new Manager(9251, 31);

b1.typeEmployee();// вызов версии из класса Employee

b2.typeEmployee();// вызов версии из класса Manager

// b2.getIdProject();// ошибка компиляции!!!

((Manager) b2).getIdProject();

Manager b3 = new Manager(9711, 35);

System.out.println(b3.getIdProject());// 35

System.out.println(b3.getId());// 9711

}

}

Объект b1 создается при помощи вызова конструктора класса Employee, и, соответственно, при вызове метода typeEmployee() вызывается версия метода из класса Employee. При создании объекта b2 ссылка типа Employee инициализируется объектом типа Manager. При таком способе инициализации ссылка на суперкласс получает доступ к методам, переопределенным в подклассе.

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

/* пример # 2 : создание объекта подкласса и доступ к полям с одинаковыми именами: Course.java: BaseCourse.java: Logic.java */

packagechapt04;

 

public class Course {

public int id = 71;

 

public Course() {

System.out.println("конструктор класса Course");

id = getId();//!!!

System.out.println(" id=" + id);

}

public int getId() {

System.out.println("getId() класса Course");

return id;

}

}

packagechapt04;

 

public class BaseCourse extends Course {

public int id = 90;// так делать не следует!

 

public BaseCourse() {

System.out.println("конструктор класса BaseCourse");

System.out.println(" id=" + getId());

}

public int getId() {

System.out.println("getId() класса BaseCourse");

return id;

}

}

packagechapt04;

 

public class Logic {

public static void main(String[] args) {

Course objA = new BaseCourse();

BaseCourse objB = new BaseCourse();

System.out.println("objA: id=" + objA.id);

System.out.println("objB: id=" + objB.id);

Course objC = new Course();

}

}

В результате выполнения данного кода последовательно будет выведено:

Конструктор класса Course

GetId() класса BaseCourse

id=0