Московский государственный индустриальный университет
Опубликован: 27.09.2006 | Доступ: свободный | Студентов: 3333 / 380 | Оценка: 4.17 / 3.79 | Длительность: 24:17:00
Специальности: Программист
Лекция 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 ). Единственное, о чем должен заботиться программист при работе с данным контейнером, — это преобразование извлекаемого объекта к его реальному типу.

Анастасия Халудорова
Анастасия Халудорова
екатерина яковлева
екатерина яковлева