Обобщения в Java: часть 1

ОГЛАВЛЕНИЕ

Аннотация

Java 5 (JDK 1.5) ввел принцип обобщений или параметризованных типов. Данная статья знакомит с принципами обобщений и показывает примеры их использования. В части II рассмотрено, как обобщения на самом деле реализованы в Java, и несколько проблем с применением обобщений.

Проблема безопасности типов

Java - строго типизированный язык. При программировании на Java во время компиляции надо знать, передается ли неверный тип параметра методу. Например, если определить:

Dog aDog = aBookReference; // ошибка

где aBookReference – ссылка типа Book, не связанная с Dog, вы получите ошибку компиляции.

Однако, к сожалению, при появлении Java, это не осуществлялось полностью в библиотеке Коллекции. Так, например, можно написать:

Vector vec = new Vector();
vec.add("hello");
vec.add(new Dog());

Не контролируется то, какой тип объекта помещается в Vector. Рассмотрим следующий пример:

package com.agiledeveloper;

import java.util.ArrayList;
import java.util.Iterator;

public class Test
{
    public static void main(String[] args)
    {
        ArrayList list = new ArrayList();
        populateNumbers(list);

        int total = 0;
        Iterator iter = list.iterator();
        while(iter.hasNext())
        {
            total += ((Integer) (iter.next())).intValue();
        }

        System.out.println(total);
    }

    private static void populateNumbers(ArrayList list)
    {
        list.add(new Integer(1));
        list.add(new Integer(2));
    }
}

В программе выше создается ArrayList, заполняется некоторыми целыми значениями Integer, а затем значения суммируются путем извлечения Integer из ArrayList.

Вывод из вышеприведенной программы - значение 3, как ожидалось.

Что если изменить метод populateNumbers() следующим образом:

private static void populateNumbers(ArrayList list)
{
    list.add(new Integer(1));
    list.add(new Integer(2));
    list.add("hello");
}

Ошибок компиляции не будет. Однако программа не выполнится правильно. Выдастся следующая ошибка при выполнении:

Exception in thread "main" java.lang.ClassCastException: 
  java.lang.String at com.agiledeveloper.Test.main(Test.java:17)…

До Java 5 в коллекциях не было безопасности типов.

Что такое обобщения?

В C++ есть такое прекрасное средство, как шаблоны. Шаблоны дают безопасность типов, в то же время, позволяя писать универсальный код, то есть не специфичный для какого-то конкретного типа. Хотя шаблоны C++ - очень мощный принцип, у него есть несколько недостатков. Во-первых, не все компиляторы хорошо поддерживают его. Во-вторых, он очень сложен в применении. Наконец, его применение имеет ряд неприятных особенностей (так можно сказать о C++ вообще, но это другая история). Когда появился Java, обошлись без большинства сложных средств C++, таких как шаблоны и перегрузка оператора.

Наконец, в Java 5 было решено ввести обобщения. Хотя обобщения – возможность писать универсальный или обобщенный код, независимый от конкретного типа – в принципе похожи на шаблоны в C++, есть ряд отличий. Например, в отличие от C++, где генерируются разные классы для каждого параметризованного типа, в Java есть только один класс для каждого обобщенного типа, независимо от того, экземпляры скольких разных типов создаются посредством него. Конечно, в обобщениях Java есть определенные проблемы, но они будут рассмотрены в части II. В части I рассматриваются преимущества.

Развитие обобщений в Java началось с проекта под названием GJ1 (обобщенный Java), начатого как расширение языка. Затем эту идею принял Процесс сообщества Java (JCP) в качестве Запроса спецификации Java (JSR) 142.