В своем путешествии в мир C# я хотел поговорить о дженериках. Дженерики существуют как в языках Java, так и в C#, но их реализация очень отличается. Цель этого сообщения в блоге – объяснить различия и сходства между ними. TL;DR Дженерики Java – это ложь, дженерики C# – нет.
Дженерики Java – это ложь
Дженерики были введены в Java 5. До этого вам приходилось манипулировать Объектами
и приводить их к нужному типу:
List apples = new ArrayList(); apples.add(new Apple()); // This is really a list of objects, so the cast is required Apple firstApple = (Apple) apples.get(0);
В предыдущем фрагменте вы должны отметить, что нет абсолютно ничего, что мешало бы вам добавить Banana
в список и привести к сбою программы во время выполнения. Кроме того, этот код по-прежнему действителен в последней версии Java (которая, как мы говорим, является Java 11). Мягко говоря, такой подход не очень безопасен и не использует систему типов так сильно, как мы могли бы ожидать.
Начиная с Java 5, можно использовать универсальную версию класса List |/:
Listapples = new ArrayList (); apples.add(new Apple()); // The cast is not required any more thanks to the generics Apple firstApple = apples.get(0);
Дело в том, что во время выполнения два предыдущих фрагмента строго эквивалентны. Действительно, дженерики Java удаляются во время компиляции, и результирующий байт-код манипулирует только Объектами
и приведениями. Это называется стирание типа . Как следствие, в Java невозможно написать такой код, как этот:
/** * Filter objects of the given type */List filterObjectsOfType(List
Действительно, тип T
стирается во время выполнения, и операция instanceof
не может быть выполнена. Вот почему объект класса часто передается в качестве аргумента метода:
/** * Filter objects of the given type */List filterObjectsOfType(List
Этот метод может быть вызван следующим образом:
ListstringsOnly = filterObjectsOfType(Arrays.asList("hello", 2), String.class); // stringsOnly contains only "hello"
Дженерики C# – это функция среды выполнения
C# generics, с другой стороны, – это совершенно другой зверь. Действительно, реальный тип сохраняется во время выполнения, и этот тип можно использовать для написания такого рода кода:
/** * Filter objects of the given type */ public IEnumerableFilterObjectsOfType (IEnumerable
Этот метод может быть вызван следующим образом:
IEnumerablestringsOnly = FilterObjectsOfType (new List
Вывод
В Java дженерики используются для написания типобезопасного кода, но эта функция ограничена, и иногда код может быть неудобным из-за механизма стирания типов. В C# это функция среды выполнения, и ее использование намного проще.
PS: Я понимаю, что код, который я написал во фрагментах, на самом деле не идиоматичен, но я хотел иметь Java и C # код настолько похож, насколько это возможно, чтобы иметь возможность сосредоточиться только на использовании дженериков.
Оригинал: “https://dev.to/rnowif/c-for-the-java-developer-generics-1c72”