Java ошибка: CAP # 1, int, где CAP # 1 - переменная типа fre sh: CAP # 1 расширяет объект от захвата? - PullRequest
0 голосов
/ 17 января 2020

С этим универсальным c классом кортежей

public class Pair< T1, T2 > {

  private final T1 first;
  private final T2 second;

  public Pair(T1 first, T2 second) {
    this.first = first;
    this.second = second;
  }

  public T1 getFirst() {
    return first;
  }

  public T2 getSecond() {
    return second;
  }

}

и этим драйвером

public class PairDriver {

  public static void main(String[] args) {

    Pair<?, ?>[] s = new Pair<?, ?>[3];
    s[0] = new Pair<String, Integer>("a", 1);
    s[1] = new Pair<String, Integer>("b", 2);
    s[2] = new Pair<String, Integer>("c", 3);

    System.out.println( s[0].getFirst().getClass().getName() ); // Should be String
    System.out.println( s[0].getSecond().getClass().getName() ); // Should be Integer

    System.out.println( s[0].getFirst() );
    System.out.println( s[0].getFirst() + "!!!" ); // Operation works

    System.out.println( s[0].getSecond() );
    System.out.println( s[0].getSecond() + 2 ); // Operation FAILS...
  }

}

я получаю следующую ошибку:

pairDriver.java:17: error: bad operand types for binary operator '+'
    System.out.println( s[0].getSecond() + 2 ); // Operation FAILS...
                                         ^
  first type:  CAP#1
  second type: int
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error
error: compilation failed

I'm запутался относительно того, почему это происходит. Все строки до строки, помеченной // Operation FAILS..., выполняются - типы кажутся правильными, и операции даже работают со строкой, но не с целым числом.

Как продолжение: я видел, как кто-то исправлял подобное ошибка путем замены подстановочного знака ? на тип. Я не понимаю, почему это сработало в их случае, но здесь оно неприменимо, потому что объявление массива с типами, такими как Pair<String, Integer>[] s = new Pair<String, Integer>[3];, приводит к другой ошибке:

pairDriver.java:5: error: generic array creation
    Pair<String, Integer>[] s = new Pair<String, Integer>[3];
                                ^
1 error
error: compilation failed

Мне не совсем понятно, почему это также случается.

Ответы [ 2 ]

3 голосов
/ 17 января 2020

Я не понимаю, почему это происходит

Что касается компилятора, вы добавляете некоторый объект в int.

Он имеет больше информации нет, потому что тип второго элемента в паре ? (как в Pair<?, ?>). Он не знает, что значение на самом деле больше Integer.

В качестве продолжения

Вы не можете создавать массивы с типами элементов, которые не могут быть переопределены. , из-за стирания типа.

Тип reifiable - это тип, в котором все известно о типе во время выполнения. Необобщенные c типы подлежат перерасчету; Типы generi c, в которых все параметры типа являются символами подстановки, можно переопределять; другие типы c не являются типичными.

Дженерики и массивы недовольны. Если вы используете дженерики, вместо этого используйте List.

List<Pair<String, Integer>> s = new ArrayList<>();
s.add(new Pair<String, Integer>("a", 1));
s.add(new Pair<String, Integer>("b", 2));
s.add(new Pair<String, Integer>("c", 3));
1 голос
/ 17 января 2020

Типы данных, добавляемых в ваш класс Pair, стираются во время выполнения. Все, что знает компилятор, это то, что данные, поступающие из getFirst() и getSecond(), являются чем-то , что расширяет Object, но он не знает, что это за нечто конкретно.

Поскольку Object имеет метод .toString(), который неявно вызывается при использовании оператора конкатенации строк, s[0].getFirst() + "!!!" работает просто отлично. Но <? extends Object> (это все, что компилятор знает о вашем типе, когда вы его используете) не подходит в качестве левой части оператора сложения.

Вы можете обойти это, приведя результат для целого числа, например:

System.out.println( (Integer) s[0].getSecond() + 2 ); 

Но обратите внимание, что это просто вы говорите компилятору: «Поверьте мне, это определенно целое число».

...