Проблема заключается в использовании конструктора, который (естественно) имеет очень специфический тип c, который затем несовместим с типом переменной, в которой вы пытаетесь его сохранить. Чтобы сделать это объяснение немного глубже в веселье и волнение подстановочных знаков типа Java, я сделал параметр типа, а не ваш Enum
. (Все это использует Java var
, чтобы сделать код немного чище. Если вы используете Java11, этот код будет хорошо компилироваться, за исключением ошибок типа и других предупреждений, которые я обсуждаю ниже. Кроме того, в вашем исходном коде есть проблема с принципом подстановки Лискова. Я пока оставлю это в покое и исправлю это ниже (4).
public interface Foo {
class A { }
class B extends A {}
class C extends B {}
class FooMap<T> {
Map<? extends T, ? extends Set<? extends T>> f; // (1)
List<? extends Set<? extends T>> fr;
public FooMap(
Map<? extends T, ? extends Set<? extends T>> f,
List<? extends Set<? extends T>> fr) {
this.f = f;
this.fr = fr;
}
static void exercise1() {
var hm = new HashMap<B, HashSet<B>>();
var list = new ArrayList<HashSet<B>>(); // (2)
var fm = new FooMap<A>(hm, list);
}
static void foo(
List<? extends Set<? extends Integer>> listOfSetsOfInts) { }
static void exercise2() {
var diffSetType = new ArrayList<HashSet<Integer>>(); // (3)
foo(diffSetType);
}
}
}
Комментарии:
(1) Также возможно избавиться от этих групповых символов. Вот некоторый альтернативный код, который скомпилирует , но вы получите предупреждения о непроверенных типах передач. Предполагая, что вы рассматриваете карту и список как прочитанные только тогда вы могли бы заменить приведенный ниже код. (Примечание: Принцип подстановки Лискова может кое-что сказать по этому поводу; см. (4) ниже.) Как только вы разрешите мутацию, все станет сложнее.
Map<T, Set<T>> f;
List<Set<T>> fr;
public FooMap(
Map<? extends T, ? extends Set<? extends T>> f,
List<? extends Set<? extends T>> fr) {
this.f = (Map<T, Set<T>>) f;
this.fr = (List<Set<T>>) fr;
}
(2) Конкретный тип list
- это ArrayList<HashSet<B>>
, но мы хотим использовать его, как если бы он был List<Set<A>>
, что разрешено в подстановочных знаках конструктора FooMap
. Обратите внимание, что мы проходишь явный т Введите в конструктор параметр ype, чтобы сказать, что это FooMap<A>
.
(3) Конкретный тип diffSetType
равен ArrayList<HashSet<Integer>>
, что совместимо с типом аргумента foo()
.
(4) Вам нужно немного подумать о параметре первого типа HashMap
, так как мы хотим удовлетворить принцип замены Лискова, что означает удовлетворение «производитель расширяет, потребитель супер» (PECS Правило Первый параметр Map
является типом «потребителя», поэтому мы действительно должны написать такой код:
class FooMap<T> {
Map<T, Set<T>> f;
List<Set<T>> fr;
public FooMap(
Map<? super T, ? extends Set<? extends T>> f,
List<? extends Set<? extends T>> fr) {
this.f = (Map<T, Set<T>>) f;
this.fr = (List<Set<T>>) fr;
}
static void exercise1() {
var hmA = new HashMap<A, HashSet<B>>();
var hmB = new HashMap<B, HashSet<B>>();
var hmC = new HashMap<C, HashSet<B>>();
var list = new ArrayList<HashSet<B>>();
var fm1 = new FooMap<A>(hmA, list); // okay
var fm2 = new FooMap<B>(hmA, list); // okay
var fm3 = new FooMap<C>(hmA, list); // type error (5)
var fm4 = new FooMap<B>(hmB, list); // okay
var fm5 = new FooMap<B>(hmC, list); // type error (6)
var fm6 = new FooMap<C>(hmC, list); // type error (7)
}
(5) HashSet<B>
из list
не соответствует ? extends Set<? extends C>
(6) HashMap<C, HashSet<B>>
из hmC
не соответствует Map<? super B, ? extends Set<? extends B>>
, поскольку C
не соответствует ? super B
.
(7) hmC
is HashMap<C, HashSet<B>>
; HashSet<B>
не соответствует ? extends Set<? extends C>