Невозможно привести к неопределенный вложенный тип с обобщениями

У меня есть два класса с вложенными обобщениями. Есть ли способ избавиться от несоответствия типов

: невозможно преобразовать из Msg > в Msg > ? В последнем назначении

public class Value<V> {
    V   val;

    public Value(V val) {
        this.val = val;
    }
    @Override
    public String toString() {
        return "" + val;
    }
}

public class Msg<T> {

    T holder;

    public Msg( T holder) {
        this.holder = holder ;
    }
    public String toString() {
        return "" + holder;
    }

    public static void main(String[] args) {
        Msg<Value<String>>strMsg = new Msg(new Value<String>("abc"));
        // This is OK
        Msg<?>objMsg = strMsg;
        // Type mismatch: cannot convert from Msg<Value<String>> to Msg<Value<?>>   
        Msg<Value<?>>objMsg = strMsg;
    }
}
10
задан Powerlord 26 August 2010 в 13:48
поделиться

5 ответов

Используйте следующее:

Msg<? extends Value<?>> someMsg = strMsg;

Проблема в том, что ? в Msg> objMsg НЕ способны к преобразованию захвата. Это не "Сообщение из Значения из некоторого типа. Это "Сообщение из Значения из ]ANY type".

Это также объясняет, почему вместе с изменением объявления я также переименовал переменную в someMsg. Value не может быть просто любой Объект.Он должен принадлежать к какому типу (Строка в этом примере).


Более общий пример

Рассмотрим более общий пример List>. Аналогично исходному сценарию, List> может НЕ захватывать-преобразовывать Список<Список<Целое число>>.

    List<List<Integer>> lolInt = null;

    List<List<?>> lolAnything = lolInt;         // DOES NOT COMPILE!!!
    // a list of "lists of anything"

    List<? extends List<?>> lolSomething = lolInt;   // compiles fine!
    // a list of "lists of something"

Вот еще один способ взглянуть на это:

  • Java generics инвариантен к типу
  • Существует преобразование из Integer в Number , но List< Целое число > не является Списком< Число >
    • Аналогично, Список<Целое> может быть преобразовано с захватом с помощью List , но List< List > не является List< List >
  • Используя ограниченный подстановочный знак, List Число > может захватывать-преобразовывать List< Integer >
    • Аналогично, List List > может захватить-преобразовать List< List >

Тот факт, что некоторые ? может захватывать, а другие не могут также объясняет следующий фрагмент:

    List<List<?>> lolAnything = new ArrayList<List<?>>(); // compiles fine!

    List<?> listSomething = new ArrayList<?>(); // DOES NOT COMPILE!!!
        // cannot instantiate wildcard type with new!

Связанные вопросы

См. также

18
ответ дан 3 December 2019 в 16:28
поделиться

Мой ответ похож на другой, но, надеюсь, более понятный.

List<List<?>> is a list of (lists of anything).

List<List<String>> is a list of (lists of strings).

Последнее не может быть преобразовано в первое, потому что это позволит вам добавить List в ваш List>, что явно будет нарушено.

Обратите внимание, что правила для этого не меняются, если вы замените List каким-либо типом, у которого нет .add. Для этого Java потребуется ковариантность сайта объявления и/или контравариантность (например, IEnumerable в C# или List[+A] в Scala). Java имеет только ковариантность и контравариантность сайта использования (? extends X, ? super X).

3
ответ дан 3 December 2019 в 16:28
поделиться

У ILMTitan есть хорошее решение, и если вы не хотите делать класс специфичным для Value, вы также можете использовать базовый тип вместо дженериков на этом этапе, потому что вы отключите функцию безопасности, но есть вдали. Возможно, вы даже сможете передать параметр, чтобы сделать этот метод более универсальным, но ключ — «@SuppressWarnings».

@SuppressWarnings("unchecked")
Msg<Value<?>> convert()
{
    return (Msg<Value<?>>) this;
}
0
ответ дан 3 December 2019 в 16:28
поделиться

Хотя параметр универсального типа содержит подстановочный знак, он сам по себе не является подстановочным знаком. При присвоении переменной (Msg) универсального типа без подстановочных знаков T присваиваемый объект должен иметь точно T универсальный тип. (включая все параметры универсального типа T, подстановочные и не подстановочные знаки). В вашем случае T — это Value, тип которого не совпадает с типом Value.

Что вы можете сделать, поскольку Value можно присвоить Value, это использовать подстановочный знак:

Msg<? extends Value<?>> a = new Msg<Value<String>>();
3
ответ дан 3 December 2019 в 16:28
поделиться

Не прямой ответ, но я настоятельно рекомендую прочитать: http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf чтобы лучше понять дженерики.

1
ответ дан 3 December 2019 в 16:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: