Опубликован: 27.09.2006 | Уровень: для всех | Доступ: свободно
Лекция 10:

Основы объектно-ориентированного программирования

Интерфейс Figure определяет геометрическую фигуру, которая характеризуется периметром и площадью. При этом конкретными реализациями этой абстрактной идеи могут быть "нульугольник" (пустое множество), "одноугольник" (точка), "двуугольник" (отрезок) и многоугольник. Каждый из этих классов имеет свою особую внутреннюю структуру: "одноугольник" содержит координаты его единственной точки, "двуугольник" — двух его концевых точек, а класс Polygon (многоугольник) вообще выведен из класса Deq, что позволяет ему хранить координаты всех его вершин. Каждый из этих классов обеспечивает свои варианты реализации для всех методов, имеющихся в описании интерфейса.

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

Динамический поиск метода никогда не используется в следующих ситуациях:

  • для методов, объявленных с ключевым словом static ;
  • для методов, объявленных с ключевым словом private ;
  • для методов, объявленных с ключевым словом final ;
  • для всех методов final -класса.

Поясним смысл этих и некоторых других ключевых слов языка Java, которые были использованы в приведенных выше примерах. Ключевое слово final, примененное к методу, запрещает переопределять его в выведенных классах. Применение его к полю данных превращает эти данные в неизменяемые (константу). Особенно часто для этой цели используется комбинация двух ключевых слов — static final. Будучи примененным к описанию класса, final запрещает использование данного класса в качестве базового.

Квалификаторы доступа private, protected и public определяют доступность данных или метода, реализуя возможность инкапсуляции. Только методы, описанные с использованием ключевого слова public, являются общедоступными. Именно они определяют интерфейс объекта. Все внутренние данные объекта, как правило, описываются с квалификатором private, что запрещает работу с ними извне объекта. Ключевое слово protected обеспечивает работу с так описанными компонентами методам выведенных классов. Во всех рассмотренных выше примерах интерфейс объекта (его public -компоненты и методы) был отделен пустой строкой от компонент, являющихся его внутренней реализацией ( private и protected данные и методы).

Теперь мы в состоянии полностью объяснить программу "Здравствуй, мир!", с которой в самом начале книги началось знакомство с языком Java.

Текст программы

public class Hello {
    public static void main(String[] args) {    
        System.out.println("Здравствуй, мир!");
    }
}

Общедоступный ( public ) статический ( static ) метод main класса Hello, с которого начинается выполнение программы, получает в качестве аргумента массив строк args, не возвращая после своего завершения никакого результата (являясь void -методом). Выполнение main сводится к вызову метода println с аргументом "Здравствуй, мир!" для объекта, на который ссылается поле (компонента) out объекта System.

Контейнеры

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

Определение 10.7. Контейнерные классы (container classes) — классы, которые используются как структуры данных, содержащие набор элементов.

Пакет java.util предоставляет интерфейс Enumeration и классы Vector, Stack, Dictionary, Hashtable и BitSet, предназначенные для решения сформулированной задачи при программировании на языке Java. По целому ряду причин мы не будем использовать классы этого пакета в нашем курсе.

Стандартная библиотека (STL) языка C++ содержит более широкий набор так называемых стандартных контейнеров. Используемые нами в данной секции имена классов и методов будут в значительной мере напоминать имена из этой стандартной библиотеки, более подробное знакомство с которой предусмотрено в рамках последующего курса "Методы хранения и обработки информации".

Определение 10.8. Основными контейнерами являются вектор (vector), перечисление (enumeration), динамический вектор (dynamic vector), стек (stack), очередь (queue), дек (deq), множество (set), одно- и двусвязные списки (lists).

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

Использование векторов (так называют массивы) нам уже хорошо знакомо, а пример работы с перечислением приведен ниже. В нем применяется интерфейс Enumeration, очень похожий на тот, что определен в пакете java.util. Этот интерфейс задает новый тип объектаконтейнер, который содержит внутри себя набор других объектов и позволяет извлекать из него эти объекты один за другим (в неизвестном порядке), предварительно выясняя, осталось ли в нем что-либо.

Пример интерфейса

interface Enumeration {
    // Есть ли еще элементы?
    public boolean hasMoreElements();
    // Взять следующий элемент.
    public Object nextElement(); 
}
// Реализация перечисления для работы с целыми числами.
class Enum implements Enumeration {
    // Вектор, в котором хранятся числа.
    private int[] values;
    // Количество уже извлеченных чисел.
    private int   current;

    // Конструктор.
    public Enum(int[] values) {
        this.values = values;
        current = 0;
    }
    public boolean hasMoreElements() {
        return current < values.length;
    }
    public Object nextElement() {
        return new Integer(values[current++]);
    }
    // Тестовая программа для работы с перечислением.
    public static void main(String[] args) {
        int[] val = new int[7];
        for (int i=0; i<7; i++)
            val[i] = 17 + i;
        Enum e = new Enum(val);
        while (e.hasMoreElements()) {
            System.out.println( ((Integer)(e.nextElement()))
                                .intValue() );
        }
    }
}

Важным моментом здесь является то, что целые числа в языке Java не являются объектами, а из перечисления Enumeration, как это следует из его интерфейса, должны извлекаться объекты. Справиться с этой проблемой помогает класс Integer, определенный в пакете java.lang, обеспечивающий преобразование целого числа в объект "целое число" и обратно. При извлечении очередного элемента с помощью метода nextElement из целого числа, хранящегося в массиве values, конструируется объект Integer, который и возвращается в качестве результата.

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

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

Пример интерфейса

interface Vector {
    // Конструктор.
    public Vector();
    // Построить перечисление из вектора.
    public Enumeration elements();
    // Пуст ли вектор?
    public boolean isEmpty();	
    // Сделать вектор пустым.
    public void removeAllElements();
    // Получить значение элемента.
    public Object elementAt(int index);
    // Изменить значение элемента.
    public void setElementAt(Object obj, int index);
    // Удалить элемент.
    public void removeElementAt(int index);
    // Добавить элемент в заданную позицию.
    public void insertElementAt(Object obj, int index);
    // Добавить элемент в конец вектора.
    public void addElement(Object obj);
}

Этот интефейс содержит метод elements(), возвращающий контейнер типа Enumeration, что позволяет работать с динамическим вектором, как с перечислением. Назначение остальных методов вполне ясно из комментариев к ним.

Отметим, что элементами этого контейнера могут быть произвольные объекты. В него можно поместить, например, несколько элементов типа Enumeration, несколько строк (тип String ) и векторов (тип Vector ). Единственное, о чем должен заботиться программист при работе с данным контейнером, — это преобразование извлекаемого объекта к его реальному типу.

Анастасия Халудорова
Анастасия Халудорова
подавляющее большиство фукций на пространстве последовательостей?
екатерина яковлева
екатерина яковлева
как получить сертификат,что для этого нужно?
Дмитрий Карпов
Дмитрий Карпов
Россия, Нижний Новгород
Антон Никитин
Антон Никитин
Россия, Хабаровск