Каким образом разница в использовании Java-сайта сравнивается с отклонениями сайта объявления С#?

Я понимаю, что указание дисперсии для генериков в С# происходит на уровне объявления типа: когда вы создаете свой общий тип, вы указываете дисперсию для аргументов типа. В Java, с другой стороны, указывается дисперсия, в которой используется общий тип: при создании переменной какого-то общего типа вы указываете, как могут варьироваться аргументы своего типа.

Каковы плюсы и минусы для каждого варианта?

Ответ 1

Я просто собираюсь ответить на различия между различием между объявлениями и сайтом-сайтом, поскольку в то время как С# и Java generics отличаются многими другими способами, эти различия в основном ортогональны к дисперсии.

Во-первых, если я правильно помню, что различие между сайтом и сайтом строго более мощное, чем дисперсия объявления-сайта (хотя и ценой его выполнения), или, по крайней мере, шаблоны Java (которые на самом деле более эффективны, чем дисперсия на сайте), Эта повышенная мощность особенно полезна для языков, в которых используются конструкторы с выраженным состоянием, такие как С# и Java (но Scala значительно меньше, тем более, что его стандартные списки неизменяемы). Рассмотрим List<E> (или IList<E>). Поскольку у него есть методы для добавления E и получения E, он является инвариантным относительно E, и поэтому дисперсия объявления-сайта не может быть использована. Однако с помощью дисперсии с использованием сайта вы можете просто сказать List<+Number>, чтобы получить ковариантное подмножество List и List<-Number>, чтобы получить контравариантное подмножество List. На языке объявления-сайта разработчик библиотеки должен будет создавать отдельные интерфейсы (или классы, если вы разрешаете множественное наследование классов) для каждого подмножества, и List расширять эти интерфейсы. Если разработчик библиотеки этого не делает (обратите внимание, что С# IEnumerable выполняет только небольшое подмножество ковариантной части IList), тогда вам не повезло, и вам приходится прибегать к тем же неприятностям, что вам нужно сделать на языке без какой-либо дисперсии.

Таким образом, преимущества наследования с использованием сайта наследования наследования-сайта. Преимущество наследования наследования-наследования над наследованием на сайте -это в основном сводка для пользователя (при условии, что разработчик выполнил усилия по разделению каждого класса/интерфейса на его ковариантную и контравариантную части). Для чего-то вроде IEnumerable или Iterator, приятно не указывать ковариацию каждый раз, когда вы используете интерфейс. Это особенно раздражало Java, используя длительный синтаксис (за исключением бивариантности, для которого Java-решение в основном идеально).

Конечно, эти две особенности языка могут сосуществовать. Для параметров типа, которые являются естественно ковариантными или контравариантными (например, в IEnumerable/Iterator), объявите это в объявлении. Для параметров типа, которые являются естественно инвариантными (например, в (I)List), объявляйте, какую дисперсию вы хотите каждый раз, когда используете ее. Просто не указывайте дисперсию использования сайта для аргументов с дисперсией объявления-сайта, так как это просто путает вещи.

Есть и другие более подробные проблемы, которые я не занимал (например, как шаблоны на самом деле более мощные, чем вариация на сайте), но я надеюсь, что это ответит на ваш вопрос на ваш контент. Я признаю, что я склонен к различию в использовании сайта, но я попытался изобразить основные преимущества обоих, которые возникли в моих дискуссиях с программистами и исследователями языка.

Ответ 2

Большинство людей, похоже, предпочитают дисперсию объявления-сайта, потому что это облегчает пользователям библиотеки (в то время как это немного усложняет разработчику библиотеки, хотя я бы сказал, что разработчик библиотеки должен думать о дисперсии, независимо от того, где фактически записана дисперсия.)

Но имейте в виду, что ни Java, ни С# не являются примерами хорошего дизайна языка.

В то время как Java получил правильную дисперсию и работает независимо от JVM из-за совместимых улучшений VM в Java 5 и стирании стилей, дисперсия использования сайта делает использование немного громоздким и конкретная реализация типа -erasure заслуживает заслуженной критики.

С# модель дисперсии объявления-сайта снимает нагрузку с пользователя библиотеки, но во время введения редифицированных дженериков они в основном построили правила дисперсии в своей виртуальной машине. Даже сегодня они не могут полностью поддерживать взаимную/контравариантность из-за этой ошибки (и совместимое с обратной совместимость введение классов reified collection разбило программистов на два лагеря).

Это создает трудное ограничение для всех языков, ориентированных на CLR, и является одной из причин того, что альтернативные языки программирования гораздо более оживленны в JVM, хотя кажется, что CLR обладает "более приятными функциями".

Посмотрите на Scala: Scala - полностью объектно-ориентированный, функциональный гибрид, работающий на JVM. Они используют стирающее стирание типа Java, но как реализацию универсальности, так и дисперсию (объявления-сайта) легче понять, более простую и мощную, чем Java (или С#), поскольку виртуальная машина не налагает правила о том, как дисперсия Работа. Компилятор Scala проверяет нотации переменных и может отклонить необоснованный исходный код во время компиляции вместо того, чтобы бросать исключения во время выполнения, в то время как результирующие файлы .class могут быть легко использованы из Java.

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

В то же время Scala может использовать примитивные типы без бокса их в коллекциях, как в С#, с помощью аннотации @specialized, которая сообщает компилятору Scala генерировать одну или несколько дополнительных реализаций класса или метода, специализированных для запрошенный примитивный тип.

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

Ответ 3

Недостатки дженериков стиля Java

Одним из следствий является то, что версия java работает только со ссылочными типами (или с короткими типами значений), а не с типами значений. IMO, что является самым большим недостатком, поскольку он предотвращает появление высокопроизводительных дженериков во многих сценариях и требует ручной записи специализированных типов.

Он не гарантирует, что такой инвариант, как "Этот список содержит только объекты типа x" и требует проверки времени выполнения на каждом геттере. Обычный тип действительно существует.

При использовании отражения вы не можете запрашивать экземпляр общего объекта, который имеет его общие параметры.

Преимущества дженериков стиля Java

Вы получаете дисперсию/можете различать разные общие параметры.

Ответ 4

Java: генерические переменные с использованием-site с Java 5. Сломанные ковариантные массивы с другим синтаксисом с 1.0. Информация о дженериках типа runtime отсутствует.

С#: Привилегии с использованием параметров сайта с С# 2.0. Добавлено отклонение сайта объявления в С# 4.0. Сломанные ковариантные массивы с другим синтаксисом с 1.0 (идентичная проблема с Java). "reified" generics означает, что информация типа не теряется во время компиляции.

Scala: как вариант использования сайта/объявления-сайта с ранних версий языка (по крайней мере с 2008 года). Массивы не являются отдельной функцией языка, поэтому вы используете одни и те же правила синтаксиса и правил дисперсии типов. Некоторые коллекции реализуются на уровне VM с массивами JVM, поэтому вы получаете равную или лучшую производительность во время выполнения по сравнению с Java-кодом.

Чтобы разработать проблему безопасности типа массива С#/Java: вы можете наложить собаку [] на Pet [] и добавить кошку и вызвать ошибку времени выполнения, которая не попадает во время компиляции. Scala реализовано правильно.