Универсальный нижний предел в Java не компилируется даже при передаче суперкласса - PullRequest
4 голосов
/ 08 мая 2019

List<? super IOException> означает, что список может содержать IOException объектов или любой объект super класса IOException. Тогда почему нижняя строка 2 не компилируется?

Также в строке 3 FileNotFoundException это не класс super IOException. Тогда почему он компилируется?

List<? super IOException> myList =  new ArrayList<Exception>();
myList.add(new Exception());     //Line 2 This line do not compile
myList.add(new FileNotFoundException());  //Line 3 This compiles

Ответы [ 3 ]

7 голосов
/ 08 мая 2019

Нижняя граница подстановочного знака задает нижнюю границу для аргумента типа, а не для допустимых типов List.Аргумент типа может быть чем-то таким конкретным, как IOException, но он может быть настолько общим, насколько мы можем получить: Object.

При добавлении Exception тип элемента слишком общий, какэлемент, потому что параметр типа может быть слишком специфичным для него - это может быть IOException.Компилятор не позволит вам добавить Exception к чему-то, что может занять только IOException с, поэтому он генерирует ошибку.

Это не происходит с FileNotFoundException, потому что независимо от того, какспецифический параметр типа, он не будет более конкретным, чем IOException (нижняя граница), поэтому FileNotFoundException, который является подклассом IOException, допустим во всех случаяхтак что компилятор это позволяет.

2 голосов
/ 08 мая 2019

Это:

myList.add(new FileNotFoundException());

компилируется, потому что FileNotFoundException равно IOException, так же как равно * Exception, поэтому оно удовлетворяетграница myList.

This:

myList.add(new Exception());

делает не компиляцией, потому что компилятор не знает, какой точный тип список(он не проверяет, что было назначено для varaible, он только смотрит на его объявленный тип), поэтому он не знает, имеет ли назначенный ему список тип, который соответствует супертипу IOException, но не Exception.

Это может произойти, если в иерархии между Exception и IOException существует промежуточный класс.Если список действительно имел этот тип, Exception может не совпадать с границей фактического списка, назначенного для myList.

Компилятор не проверяет ни полную иерархию классов, ни то, что было назначено.Он выполняет только базовую проверку, которая всегда позволяет избежать ошибок во время выполнения.

Это также верно в более общем случае, когда «логически» нет пути к коду, который может вызвать ошибку, но компиляция все равно не удалась.

0 голосов
/ 08 мая 2019

myList ссылается на список, который может быть List<IOException> или List<Exception> или List<Object>.Строка 2 не компилируется, потому что у нас может быть List<IOException>, и объект Exception не поместится туда

File-NotFoundException также может быть добавлен к любому из этих трех типов.Это сложно, потому что FileNotFoundException является подклассом IOException, а ключевое слово говорит: super.

Компилятор просматривает ссылочный тип: List<? super IOException> все возможные типы так:

List<Object>
List<Exception>
List<IOException>

затем он пересекает строку myList.add(new Exception()); и видит, что не может скомпилироваться, потому что не может поместиться в List<IOException>

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