Сегодня я прочитал несколько статей о ковариантности, контравариантности (и инвариантности) в Java. Я читал статьи в Википедии на английском и немецком языках, а также некоторые другие сообщения в блогах и статьи IBM.
Но я все еще немного не понимаю, о чем они? Некоторые говорят, что это связано с отношениями между типами и подтипами, некоторые говорят о преобразовании типов, а некоторые говорят, что это используется для определения того, переопределяется метод или перегружен.
Поэтому я ищу простое объяснение на простом английском языке, которое покажет новичку, что такое ковариация и контравариантность (и инвариантность). Плюс к простому примеру.
Ответы:
Все вышеперечисленное.
По сути, эти термины описывают, как на отношение подтипов влияют преобразования типов. То есть, если
A
иB
являются типами,f
является преобразованием типа и ≤ отношение подтипа (т.е.A ≤ B
означает, чтоA
это подтипB
), мы имеемf
ковариантно, еслиA ≤ B
следует, чтоf(A) ≤ f(B)
f
контравариантно, еслиA ≤ B
следует, чтоf(B) ≤ f(A)
f
инвариантен, если ни одно из вышеперечисленных условий не выполняетсяРассмотрим пример. Пусть
f(A) = List<A>
гдеList
указаноЯвляется
f
ковариантны, контравариантен или инвариант? Ковариантный будет означать , чтоList<String>
является подтипомList<Object>
, контравариантно чтоList<Object>
является подтипомList<String>
и инвариантно , что ни является подтип других, т.е.List<String>
иList<Object>
являются неконвертируемыми типами. В Java верно последнее, мы говорим (несколько неформально), что дженерики инвариантны.Другой пример. Пусть
f(A) = A[]
. Являетсяf
ковариантны, контравариантен или инвариант? То есть, является ли String [] подтипом Object [], Object [] подтипом String [] или не является ни одним из подтипов другого? (Ответ: В Java массивы ковариантны)Это все еще было довольно абстрактным. Чтобы сделать его более конкретным, давайте посмотрим, какие операции в Java определены в терминах отношения подтипа. Самый простой пример - присвоение. Заявление
будет компилироваться, только если
typeof(y) ≤ typeof(x)
. То есть мы только что узнали, что утвержденияне будет компилироваться на Java, но
воля.
Другой пример, в котором отношение подтипа имеет значение, - это выражение вызова метода:
Неформально говоря, этот оператор оценивается путем присвоения значения
a
первому параметру метода, затем выполнения тела метода и последующего присвоения возвращаемого значения методаresult
. Подобно простому присваиванию в последнем примере, «правая часть» должна быть подтипом «левой стороны», то есть этот оператор может быть действительным, только еслиtypeof(a) ≤ typeof(parameter(method))
иreturntype(method) ≤ typeof(result)
. То есть, если метод объявлен:ни одно из следующих выражений не будет компилироваться:
но
воля.
Другой пример, когда подтипы имеют приоритетное значение. Рассматривать:
где
Неформально среда выполнения перепишет это так:
Чтобы отмеченная строка скомпилировалась, параметр метода переопределенного метода должен быть супертипом параметра переопределенного метода, а тип возвращаемого значения - подтипом переопределенного метода. Формально говоря, он
f(A) = parametertype(method asdeclaredin(A))
должен быть как минимум контравариантным, а еслиf(A) = returntype(method asdeclaredin(A))
должен быть как минимум ковариантным.Обратите внимание на «как минимум» выше. Это минимальные требования, которые должен соблюдать любой разумный статически безопасный объектно-ориентированный язык программирования, но язык программирования может быть более строгим. В случае Java 1.4 типы параметров и возвращаемые типы методов должны быть идентичными (за исключением стирания типа) при переопределении методов, то есть
parametertype(method asdeclaredin(A)) = parametertype(method asdeclaredin(B))
при переопределении. Начиная с Java 1.5, ковариантные возвращаемые типы разрешены при переопределении, т.е. следующие будут компилироваться в Java 1.5, но не в Java 1.4:Надеюсь, я все осветил - точнее, поцарапал поверхность. Тем не менее я надеюсь, что это поможет понять абстрактную, но важную концепцию вариативности типов.
источник
A ≤ B
. Эта запись делает вещи намного более простыми и значимыми. Хорошее чтение ...Взяв систему типов java, а затем классы:
Любой объект некоторого типа T может быть заменен объектом подтипа T.
ВАРИАНТ ТИПА - МЕТОДЫ КЛАССА ИМЕЮТ СЛЕДУЮЩИЕ ПОСЛЕДСТВИЯ
Видно, что:
Теперь соотнесите B с подтипом A. Следующие более строгие типы могут быть введены с более конкретными знаниями. В подтипе.
Ковариация (доступна в Java) полезна, чтобы сказать, что в подтипе возвращается более конкретный результат; особенно это видно, когда A = T и B = S. Контравариантность говорит о том, что вы готовы к более общему аргументу.
источник
Дисперсия - это отношения между классами с разными параметрами дженериков. Их отношения - причина, по которой мы можем использовать их.
Дисперсия Co и Contra - довольно логичные вещи. Система языковых типов заставляет нас поддерживать логику реальной жизни. Это легко понять на примере.
ковариации
Например, вы хотите купить цветок, и в вашем городе есть два цветочных магазина: магазин роз и магазин ромашек.
Если вы спросите кого-нибудь, "где находится цветочный магазин?" и кто-нибудь скажет вам, где находится магазин роз, можно? да, потому что роза - это цветок, если вы хотите купить цветок, вы можете купить розу. То же самое касается и тех, кто ответил вам адресом магазина ромашек. Это пример ковариации : вам разрешено приведение
A<C>
кA<B>
, гдеC
является подклассомB
, ifA
производит общие значения (возвращается в результате функции). Ковариация - это производители.Типы:
На вопрос «где находится цветочный магазин?», Ответ «там магазин роз»:
Контравариантность
Например, вы хотите подарить девушке цветок. Если ваша девушка любит любой цветок, можете ли вы считать ее человеком, который любит розы, или человеком, который любит ромашки? да, потому что если она любит любой цветок, она полюбит и розу, и ромашку. Это пример контравариантности : вам разрешено приведение
A<B>
кA<C>
, гдеC
является подклассомB
, еслиA
потребляет общее значение. Контравариантность касается потребителей.Типы:
Вы рассматриваете свою девушку, которая любит любой цветок, как человека, любящего розы, и дарите ей розу:
Вы можете найти больше в источнике .
источник