Не проверено приведение типа generi c к тому же типу - PullRequest
2 голосов
/ 11 февраля 2020

Следующий код генерирует предупреждение Unchecked cast: 'T' to 'U' в IntelliJ IDEA:

interface A {}
class B<T extends A, U extends A> {
    void f() {
        final T t = null;
        final U u = (U) t;
    }
}

Это не имеет смысла для меня, поскольку T и U определены как один и тот же тип. В чем проблема?

Ответы [ 4 ]

5 голосов
/ 11 февраля 2020

T и U не определены как один и тот же тип. Они оба определены как extends A, что означает, что T и U могут быть несвязанными классами, которые реализуют интерфейс A. Следовательно, приведение не является безопасным.

Единственное безопасное приведение, которое вы можете сделать, - приведение ссылок типа T или U к типу A. Конечно, вам не нужен такой актерский состав. Вы можете просто назначить их переменной типа A.

1 голос
/ 11 февраля 2020
    final T t = null;
    final U u = (U) t;

Хотя этот флажок снят, на самом деле это безопасно, поскольку null может быть приведен к любому ссылочному типу без ClassCastException.

Однако компилятор не учитывает значение ненулевая ссылка, когда вы ее разыгрываете: это просто «некоторые» T. Это пример того, где вы, программист, знаете больше о типах, чем компилятор, потому что вы знаете, что t == null, поэтому вы можете законно попросить компилятор доверять вам, добавив приведение и @SuppressWarnings.

Но если бы t было ненулевым, это не всегда было бы безопасно. T и U - это разные типы: «что-то, что расширяет A» и «что-то (может быть, то же самое, может быть, нет), которое расширяет A».

Чтобы сделать это немного немного конкретнее, вот эквивалентный пример:

class B<T extends Serializable, U extends Serializable> {
  U method(T t) {
    return (U) t;
  }
}

String s = new B<Integer, String>().method(1);

Это не удастся с ClassCastException, потому что Integer не является String.

Если вы не Чтобы они не были разных типов, удалите один из них (и, конечно, актерский состав).

1 голос
/ 11 февраля 2020

Хотя оба T и U расширяются A, они не относятся к одному и тому же типу. Следовательно, вы не можете разыгрывать от одного к другому.

Обратите внимание:

class D implements A {}
class E implements A {}
B<D, E> b;

Вы не можете разыграть от D до E.

0 голосов
/ 11 февраля 2020

Родитель:

interface A {
} 

Ребенок:

class B implements A {

}

class C implements A {

}

В приведенном выше примере A является родительским элементом B и C.

Пример:

Приведенный ниже код будет работать нормально.

  A a = new B();

  B b = (B)a;

Это вызовет исключение класса Cast.

  B b = new B();

  C c = (C) b;

Вы не можете набирать тип с типом Siblings. Это потому, что вы можете попытаться получить доступ к методам / свойствам, которые могут присутствовать в результирующем классе.

То же самое может быть в String, Integer, Object. Объект parent
Integer и String являются дочерними для класса Object, но вы не можете привести их к классу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...