Я слышал, что реализация Java Generics не так хороша, как реализация С#. В этом синтаксис выглядит схоже, что это не соответствует стандарту реализации Java, или это религиозная точка зрения?
С# vs Java generics
Ответ 1
ссылка streloksi делает отличную работу по разложению различий. Быстрое и грязное резюме, хотя...
В терминах синтаксиса и использования. Синтаксис примерно одинаковый между языками. Несколько причуд здесь и там (особенно в ограничениях). Но в основном, если вы можете прочитать один, вы, скорее всего, будете читать/использовать другой.
Самая большая разница в реализации.
Java использует понятие стирания типа для реализации дженериков. Короче говоря, базовые скомпилированные классы на самом деле не являются общими. Они скомпилируются в Object и casts. По сути, дженерики Java являются артефактом времени компиляции и могут быть легко искажены во время выполнения.
С#, с другой стороны, благодаря CLR, реализует обобщения, все они доходят до байтового кода. Для поддержки дженериков в версии 2.0 CLR предприняло несколько изменений. Преимуществами являются повышение производительности, проверка и отражение безопасности в глубоком типе.
Ответ 2
Разница сводится к дизайнерскому решению Microsoft и Sun.
Generics в Java реализуется с помощью типа erasure компилятор, что означает, что проверка типа происходит во время компиляции, а информация о типе удаляется. Этот подход был применен, чтобы сохранить устаревший код совместимым с новым кодом с использованием дженериков:
Из учебников по Java, Generics: Type Erasure:
Когда генерируется типичный тип, компилятор переводит эти типы метод, называемый стиранием стилей - a процесс, когда компилятор удаляет все информация, относящаяся к параметрам типа и введите аргументы внутри класса или метод. Тип erasure позволяет Java приложения, которые используют поддерживать двоичную совместимость с Java-библиотеки и приложения, которые были созданы до дженериков.
Однако, с generics в С# (.NET), стирание стилей не выполняется компилятором, а проверки типа выполняются во время выполнения, Это имеет свои преимущества в том, что информация о типе сохраняется в скомпилированном коде.
Из Википедии:
Этот выбор дизайна используется для обеспечивают дополнительную функциональность, такую что позволяет сохранение общих типов, а также как смягчение некоторых ограничений стирания (например, невозможно создавать общие массивы). Эта также означает, что нет производительность, получаемая от выполнения команд и обычно дорогостоящие преобразования бокса.
Вместо того, чтобы сказать: ".NET-генераторы лучше, чем Java-дженерики", нужно изучить разницу в подходе к внедрению дженериков. В Java кажется, что сохранение совместимости было высоким приоритетом, в то время как в .NET(при введении в версии 2.0) реализация полного преимущества использования дженериков была более высокой.
Ответ 3
Всеобъемлющее сравнение здесь, с некоторыми ссылками.
Ответ 4
Также нашел этот разговор с Андерсом Хейльсбергом, который может быть интересным. Чтобы обобщить моменты, которые Андерс Хейлсберг сделал с некоторыми дополнительными примечаниями: Java-дженерики были созданы для максимальной совместимости с существующей JVM, что привело к нескольким нечетным вещам и реализации, которые вы видите на С#:
-
Реализуйте операцию стирания типа для представления каждого общего параметризованного значения как
Object
. Хотя компилятор обеспечивает автоматическое отбрасывание междуObject
и более конкретным типом, он не устраняет негативное влияние типов приведения и бокса на производительность (например,Object
передается определенному типуMyClass
илиint
должен быть помещен вInteger
вInteger
, что было бы еще больше серьезный для С#/. NET, если они следуют типу стирания за счет пользовательских типов значений). Как сказал Андерс: "вы не получаете какой-либо эффективности выполнения" (что разрешено использование генерических средств на С#) -
Стирание типа делает информацию доступной во время компиляции, недоступной во время выполнения. Что-то, что раньше было
List<Integer>
становится простоList
без возможности восстановления параметра универсального типа во время выполнения. Это затрудняет построение сценариев генерации или динамического сценария генерации кода Java. Более свежий ответ SO показывает путь вокруг него через анонимные классы. Но без трюков что-то вроде генерации кода во время выполнения через отражение, которое получает элементы из одного экземпляра коллекции и помещает его в другой экземпляр коллекции, может не работать во время выполнения во время выполнения динамически сгенерированного кода: отражение не помогает с обнаружением несоответствия вList<Double>
по сравнению сList<Integer>
в этих ситуациях.
Но +1 для ответа, связанного с записью блога Джонатана Прайор.