Рубрики
Без рубрики

Дженерики На Java

В чем смысл дженериков? Одно из определений из Java docs: Generics allow… С пометкой java, информатика, программирование, новички.

В чем смысл дженериков?

Одно из определений из Java docs:

Дженерики позволяют вам абстрагироваться от типов. Наиболее распространенными примерами являются типы контейнеров, например, в иерархии коллекций.

по-английски:

Абстрагироваться от типа означает группировать похожие и обобщать их.

Например: что нам делать, если нам нужно сохранить имя, фамилию и адрес электронной почты нескольких людей, создаем ли мы n количество переменных для хранения и извлечения их вручную операционная мы создаем над ним абстракцию, известную как Class .

Отлично! , Теперь мы знаем, что означает абстрактный над типом, но я все еще не понимаю, насколько это выгодно для нас???

Короче говоря: Generics предоставляет нам проверку типов во время компиляции и избавляет от необходимости ручного приведения типов.

Подробнее: Давайте выясним

Давайте рассмотрим пример того, как работала коллекция до внедрения дженериков.

List numList = new ArrayList(); // 1
numList.add(new Integer(1)); // 2
Integer x = (Integer) numList.iterator().next(); // 3    

Строка 1 и строка 2 просты, мы создали ArrayList и добавили целое число.

В строке 3 у нас есть кое-что, что выглядит болезненно и, вероятно, вызовет у вас небольшое раздражение Ручное преобразование типов

Просто представьте, что вы делаете это каждый раз.

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

Это был лучший сценарий, когда, несмотря на то, что он выглядит плохо, он все равно работает что, если

List list = new ArrayList(); //1
list.add("abc"); //2
list.add(new Integer(5)); //3 

for(Object obj : list){
    Integer numbers=(Integer) obj; 
}

Строка 1 мы создали ArrayList Строка 2 мы добавляем строку в список Строка 3 мы добавляем целое число в список

Подождите, что!! Сначала мы добавили строку, а теперь целое число в один и тот же список

Хорошо, что дальше, мы перебираем список и пытаемся вручную ввести приведение его к целому числу

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

Ты знаешь, что будет дальше

ClassCastException Исключение класса 🎆 💥

Мы все знаем кого-то, кто способен на это 😉

Какие проблемы мы обнаружили до сих пор:

  1. Нам нужна абстракция поверх них, чтобы нам не нужно было каждый раз преобразовывать ее вручную
  2. Нам нужна проверка во время компиляции, чтобы спасти нас от ClassCastException

Это то, в чем нам помогает наш спаситель дженериков

Как? Давайте выясним

List listOfString = new ArrayList<>(); //1
listOfString.add("Generics"); //2
listOfString.add("are"); //3
listOfString.add("Awesome"); //4

for(String str : listOfString){ //5
     //no type casting needed, avoids ClassCastException
}

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

Также есть кое-что новое в строке 1 List ArrayList<>();

<> <>

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

Что делать, если кто-то попытается добавить целое число в приведенный выше список?

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

Итак, можем ли мы использовать дженерики только с коллекциями?

Нет, Коллекции – это всего лишь одно из мест, где мы можем использовать дженерики. Давайте посмотрим на другие места, где мы можем использовать дженерики.

Давайте начнем с малого

Универсальный интерфейс

interface Print{
  void display(T input);
}

Мы можем создавать универсальные интерфейсы, которые могут быть реализованы классами с соответствующим типом данных

class PrintInteger implements Print{

  @Override
  public void display(Integer input) {
    System.out.println("Printing an int "+input);
  }
}

Мы реализовали интерфейс печати и указали тип данных как целое число.

Генетический класс и общие методы

Давайте рассмотрим ситуацию, когда мы хотим сохранить имя, фамилию и идентификатор сотрудника, но тип данных идентификатора может быть интересным, длинным или строковым.

Код без дженериков

class EmployeeWithIntegerId {
private String firstName;
private String lastName;
private int id;
}

class EmployeeWithLongId {
private String firstName;
private String lastName;
private long id;
}

class EmployeeWithStringId {
private String firstName;
private String lastName;
private String id;
}

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

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

Код с использованием дженериков

class Employee{
  private String firstName;
  private String lastName;
  private T id;
}

T в приведенном выше коде представляет тип данных нашего идентификатора, который будет определен нами при создании экземпляра класса.

Является ли T обязательным для использования?

Нет, T – это просто наиболее часто используемый вариант, но он не является обязательным. Мы можем использовать любой алфавит, который нам нравится, вместо T .

Для людей, которые интересуются лучшими практиками в области именования

The most commonly used type parameter names are:

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

любезно предоставлено javadocs

Теперь, когда мы используем дженерики, нам нужно было создать только один класс, где единственное, что нужно было решить, – это тип нашей переменной id.

Хорошо, но как будут работать геттеры, сеттеры и конструкторы??

Конструктор

  public Employee(String firstName, String lastName, T id) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.id = id;
  }

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

Добытчики и сеттеры

  public T getId() {
    return id;
  }

  public void setId(T id) {
    this.id = id;
  }

Итак, мы определили класс, так как же мы можем его использовать??

Employee employee= new Employee<>("yash","sugandh","1234"); 

В приведенном выше примере мы создали объект класса Employee и при его создании использовали оператор <> для определения типа данных T как String.

Существует ограничение на тип данных, из-за которого мы не можем использовать примитивные типы данных, поэтому мы не можем использовать int, мы должны использовать Integer, Long вместо long и так далее.

Теперь мы знаем о генетике и о том, как она помогает нам в коллекциях, интерфейсе, классах и методах.

Но все еще остается несколько вопросов

  1. Что такое подстановочные знаки в дженериках?
  2. Что означает ограниченный и неограниченный подстановочный знак?
  3. Как Java обеспечивает обратную совместимость от кода с дженериками к коду без дженериков?

Давайте рассмотрим все эти темы в следующем посте.

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

Увидимся в забавных газетах 🚀

Оригинал: “https://dev.to/yashsugandh/generics-in-java-3mb5”