Дженерики в Java

С помощью дженериков мы можем писать классы и методы, которые не привязаны только к одному типу. Тип данных указываются в качестве параметров, которые должны быть ссылочным типом.
Основными преимуществами дженериков являются повторное использование кода (очевидно), а также безопасность типов:
До появления дженериков (JDK 5) можно было использовать корневой класс Object в качестве члена класса, не ограничивая его одним типом. Но это было не безопасно.
Другие могут изменить ваш объект и превратить его во что угодно и вызвать ошибку, которая будет обнаружена только во время выполнения (помните, что в этом случае компилятор ничего не знает о типе данных).
С дженериками все приведения типов выполняются автоматически и безопасность.
Как это реализовано?

Компилятор Java не создает разные версии дженериков для каждого типа T.
Вместо этого он заменяет дженерики их связанными типами. Например, class Data<T extends Number>{ T num } заменяется на class Data{ Number num }.
Обратите внимание, что этот процесс также обеспечивает обратную совместимость со старыми версиями Java.
С другой стороны, нельзя написать что-то вроде этого:

ArrayList<Integer> list = new ArrayList<>();
// won't compile
System.out.println(list instanceof ArrayList<Integer>);
// but this is true
System.out.println(list instanceof ArrayList);

В то время как в C# дженерики реализованы по-другому:

Console.WriteLine(new List<string>() is List<string>); 
// that's fine in C#

простой пример безопасных типов (Java):

class Something{
    Object obj;
}
class Something{
    Object obj;
}

class SomethingGeneric<T extends Number>{
    T t;
}
// somewhere else in the code:
Something s = new Something();
s.obj = 1;
String str1 = (String) s.obj; // ClassCastException
SomethingGeneric<Integer> gen = new SomethingGeneric();
gen.t = 2;
String str2 = (String) gen.t; // won't compile
gen.t = "2"; // won't compile

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

public class GenericMethodTest {
   // generic method printArray
   public static < E > void printArray( E[] inputArray ) {
      // Display array elements
      for(E element : inputArray) {
         System.out.printf("%s ", element);
      }
      System.out.println();
   }

   public static void main(String args[]) {
      // Create arrays of Integer, Double and Character
      Integer[] intArray = { 1, 2, 3, 4, 5 };
      Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
      Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };

      System.out.println("Array integerArray contains:");
      printArray(intArray);   // pass an Integer array

      System.out.println("\nArray doubleArray contains:");
      printArray(doubleArray);   // pass a Double array

      System.out.println("\nArray characterArray contains:");
      printArray(charArray);   // pass a Character array
   }
}

Следующий пример иллюстрирует применение метода для возврата наибольшего из трех объектов Comparable.

public class MaximumTest {
   // determines the largest of three Comparable objects
   
   public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
      T max = x;   // assume x is initially the largest
      
      if(y.compareTo(max) > 0) {
         max = y;   // y is the largest so far
      }
      
      if(z.compareTo(max) > 0) {
         max = z;   // z is the largest now                 
      }
      return max;   // returns the largest object   
   }
   
   public static void main(String args[]) {
      System.out.printf("Max of %d, %d and %d is %d\n\n", 
         3, 4, 5, maximum( 3, 4, 5 ));

      System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
         6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));

      System.out.printf("Max of %s, %s and %s is %s\n","pear",
         "apple", "orange", maximum("pear", "apple", "orange"));
   }
}

Код выведет:





Max of 3, 4 and 5 is 5

Max of 6.6,8.8 and 7.7 is 8.8

Max of pear, apple and orange is pear

Ответить