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

Введение в Java Generics

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

Например, предположим, что у вас есть метод, работающий с массивом целых чисел:

public static int sum(int[] arr) {
    int sum = 0;
    for (int i : arr) {
        sum += i;
    }
    return sum;
}

Если вы хотите использовать этот метод для массива двойников, вам нужно будет создать новый метод, который принимает массив двойников в качестве параметра:

public static double sum(double[] arr) {
    double sum = 0.0;
    for (double d : arr) {
        sum += d;
    }
    return sum;
}

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

С помощью Generics вы можете создать один метод, который может работать с любым типом массива:

public static <T extends Number> double sum(T[] arr) {
    double sum = 0.0;
    for (T t : arr) {
        sum += t.doubleValue();
    }
    return sum;
}

В приведенном выше примере мы использовали параметр типа T, который расширяет класс Number. Это означает, что мы можем передать этому методу массив любого класса, который расширяет число, например Integer, Double или Float.

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

Обобщения широко используются с коллекциями в Java. Они позволяют создавать коллекции, которые могут содержать объекты любого типа, обеспечивая при этом безопасность типов во время компиляции.

Например, предположим, что вы хотите создать список, который может содержать объекты любого типа:

List<Object> list = new ArrayList<Object>();

В приведенном выше примере мы создали тип списка объектов. Это означает, что мы можем добавить в этот список объекты любого типа, включая строки, целые числа и даже пользовательские объекты.

Однако если мы попытаемся добавить в этот список объект не того типа, компилятор выдаст ошибку во время компиляции:

list.add("Hello");  // Compilation error

Это связано с тем, что список имеет тип Object, и мы пытаемся добавить в него строку.

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

List<String> list = new ArrayList<String>();

В приведенном выше примере мы создали список типа String. Это означает, что мы можем добавлять в этот список только объекты String.

Это обеспечивает безопасность типов во время компиляции, а также делает наш код более читабельным и удобным для сопровождения.

В заключение, Java Generics — это мощная функция, позволяющая писать более гибкий и повторно используемый код. Они активно используются с коллекциями в Java, чтобы обеспечить безопасность типов и сделать код более читабельным и удобным в сопровождении.