English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Основной учебник Java

Java 流程控制

Java 数组

Java 面向对象(I)

Java 面向对象(II)

Java 面向对象(III)

Обработка исключений Java

Java 列表(List)

Java Queue(队列)

Java Map集合

Java Set集合

Java 输入输出(I/O)

Java Reader/Writer

Java 其他主题

Java генерик

在本教程中,我们将通过示例了解Java泛型,如何创建泛型类和方法及其优势。

在Java中,Generic有助于创建可与不同类型的对象(数据)一起使用的类,接口和方法。因此,允许我们重用我们的代码。

意:Generic泛型不适用于基本类型(int,float,char等)。

如何使用Java泛型

要了解在Java中如何使用Generic,我们可以使用ArrayListJava集合框架的类。

ArrayList类是泛型类的一个示例。我们可以使用ArrayList来存储任何类型的数据。例如

import java.util.ArrayList;
class Main {
   public static void main(String[] args) {
      //创建一个数组列表来存储Integer 数据
      ArrayList<Integer> list1 = new ArrayList<>();
      list1.add(4);
      list1.add(5);
      System.out.println("ArrayList of Integer: " + list1);
      //创建数组列表来存储String 数据
      ArrayList<String> list2 = new ArrayList<>();
      list2.add("Four");
      list2.add("Five");
      System.out.println("ArrayList of String: " + list2);
      //创建数组列表来存储Double 数据
      ArrayList<Double> list3 = new ArrayList<>();
      list3.add(4.5);
      list3.add(6.5);
      System.out.println("ArrayList of Double: " + list3);
   }
}

Результат вывода

ArrayList of Integer: [4, 5]
ArrayList of String: [Four, Five]
ArrayList of Double: [4.5, 6.5]

В предыдущем примере мы использовали один и тот же класс ArrayList для хранения элементов типа Integer, String и Double. Из-заJava generics, это возможно.

Здесь, пожалуйста, обратите внимание на эту строку,

ArrayList<Integer> list1 = new ArrayList<>();

Мы использовали Integer в尖括никах <> .尖括ники <> в generics называютсяПараметры типа.

Параметр type используется для указания типа объекта (данных), который подходит для generics класса или метода.

Создание generics класса

Теперь мы знаем, как generics работают в Java, давайте посмотрим, как создать свой generics класс.

Пример: Создание generics класса

class Main {
  public static void main(String[] args) {
    //Инициализация generics класса целочисленными данными
    GenericsClass<Integer> intObj = new GenericsClass<>(5);
    System.out.println("Generic class returns: " + intObj.getData());
    //Инициализация generics класса строковыми данными
    GenericsClass<String> stringObj = new GenericsClass<>("Java Programming");
    System.out.println("Generic class returns: " + stringObj.getData());
  }
}
class GenericsClass<T> {
  //Переменная типа T
  private T data;
  public GenericsClass(T data) {
    this.data = data;
  }
  //Метод для возврата переменной типа T
  public T getData() {
    return this.data;
  }
}

Результат вывода

Generic class возвращает: 5
Generic class возвращает: Java Programing

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

class GenericsClass<T> {...}

Здесь T означаетПараметры типаВнутри класса Main мы создали объекты GenericsClass с именами intObj и stringObj.

  • При создании intObj типовой параметр T заменяется на Integer. Это означает, что intObj использует GenericsClass для обработки целых данных.

  • При создании stringObj типовой параметр T заменяется на String. Это означает, что stringObj использует GenericsClass для обработки строковых данных.

Создание generics метода

Как и generics классы, мы можем создавать свои generics методы в Java.

Пример: создание generics метода

class Main {
  public static void main(String[] args) {
    // использование Integer для инициализации класса
    DemoClass demo = new DemoClass();
    demo.<String>genericMethod("Java Programming");
  }
}
class DemoClass {
  // generics метод
  public <T> void genericMethod(T data) {
    System.out.println("Это generics метод.");
    System.out.println("Переданные методу данные: " + data);
  }
}

Результат вывода

Это generics метод.
Переданные методу данные: Java Programming

В примере выше мы создали generics метод genericsMethod в обычном классе (DemoClass).

public <T> void genericMethod(T data) {...}

Здесь типовой параметр <T> вставлен после модификатора (public) и перед типом возвращаемого значения (void).

Мы можем вызвать generics метод, поместив фактический тип <String> перед именем метода в скобках.

demo.<String>genericMethod("Java Programming");

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

demo.genericsMethod("Java Programming");

ограниченные типы

Обычно:Параметр typeМожет приниматьany тип данных (за исключением примитивных типов). Но если мы хотим использовать generics только для некоторых специфических типов (например, принимать данные типа Number), то можно использовать ограниченные типы.

Мы используем ключевое слово extends. Например:

<T extends A>

Это означает, что T может принимать только подтипы данных A.

Пример: ограниченные типы

class GenericsClass<T extends Number> {
  public void display() {}}
    System.out.println("This is a bounded type generics class.");
  }
}
class Main {
  public static void main(String[] args) {
    //Создание объекта GenericsClass
    GenericsClass<String> obj = new GenericsClass<>();
  }
}

В приведенном выше примере мы создалиограниченные типыGeneric class. Здесь обратите внимание на выражение

<T extends Number>

Это означает, что T может использовать только подтипы данных subclasses Number (Integer, Double и т.д.).

Но我们已经 создали объект класса generics с помощью String. Вот почему, когда мы запускаем программу, мы получаем следующую ошибку.

GenericsClass<String> obj = new GenericsClass<>();
                                                 ^
    причина: переменная типа inference variable T имеет несовместимые границы
      ограничения равенства: String
      нижние границы: Number
  where T is a type-variable:
    T extends Number declared in class GenericsClass

Преимущества generics в Java

1. Повторное использование кода

GenericЭто позволяет нам писать код, подходящий для данных различных типов. Например:

public <T> void genericsMethod(T data) {...}

Здесь мы создаем метод generics. Этот метод может использоваться для выполнения операций с данными целых чисел, строк и т.д.

2. Проверка типов в компиляции

GenericПараметр typeПредоставление информации о типах данных, используемых в коде generics.

Таким образом, можно определить любые ошибки в компиляции, что проще исправить, чем ошибки во время выполнения. Например:

//Не использовать generics
NormalClass list = new NormalClass();
//Вызов метода NormalClass
list.display("String");

В приведенном выше коде у нас есть обычный класс. Мы вызываем метод display() этого класса, передавая строковые данные.

Здесь компилятор не знает, правильны ли передаваемые значения в параметрах. Но посмотрим, что произойдет, если использовать классы-генерики.

//Использование generics
GenericsClass<Integer> list = new GenericsClass<>();
// Вызов метода GenericsClass
list2.display("String");
В приведенном выше коде у нас есть генерический класс. Здесь типовые параметры представляют собой данные Integer, обрабатываемые этим классом.
Таким образом, при передаче строковых данных в параметрах компилятор генерирует ошибку.

3. Использование генериков с集合ами

Контейнерный интерфейс использует концепцию генериков Java. Например:

// Создать ArrayList типа string
ArrayList<String> list1 = new ArrayList<>();
// Создать ArrayList типа integer
ArrayList<Integer> list2 = new ArrayList<>();

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

Как и ArrayList, другие коллекции (LinkedList, Queue, Maps и т.д.) также являются генериками Java.