Подтвердить что ты не робот

Ограниченные возможности Java: ошибка ввода типа? (Вызов метода, JLS 15.12.2.7)

Для следующего фрагмента кода:

import java.util.List;

public class Main {
    interface Interface1<T> {}
    interface Interface2<T> extends Interface1<T> {}
    static class Bound {}
    interface BoundedI1<T extends Bound> extends Interface1<T> {}
    interface BoundedI2<T extends Bound> extends Interface2<T> {}

    public static void main(String[] args) {
        test((List<BoundedI2<?>>) null);
        //test2((List<BoundedI2<?>>) null);
    }

    public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }

    public static void test2(List<? extends Interface1<? extends Bound>> list) {}
}

Компилятор в порядке с первым вызовом, но жалуется, если я раскомментирую второй. Является ли это ошибкой в ​​системе вывода типов, или кто-нибудь может объяснить, почему здесь действуют правила вывода в JLS?

Протестировано на Oracle JDK 6u43 и 7u45.

UPDATE: Кажется, что eclipsec принимает его просто отлично. К сожалению, я не могу изменить нашу toolchain: P, но интересно найти различия в компиляторах.

Сообщение об ошибке, напечатанное ideone (крутой инструмент btw):

Main.java:12: error: method test2 in class Main cannot be applied to given types;
        test2((List<BoundedI2<?>>) null);
        ^
  required: List<? extends Interface1<? extends Bound>>
  found: List<BoundedI2<?>>
  reason: actual argument List<BoundedI2<?>> cannot be converted to List<? extends Interface1<? extends Bound>> by method invocation conversion

UPDATE 2: Это компилируется отлично, что указывает на то, что компилятор считает, что BoundedI2<?> можно присваивать Interface1<? extends Bound>, что, кажется, более прямо противоречит JLS:

public class Main {
    interface Interface1<T> {}
    interface Interface2<T> extends Interface1<T> {}
    static class Bound {}
    interface BoundedI1<T extends Bound> extends Interface1<T> {}
    interface BoundedI2<T extends Bound> extends Interface2<T> {}

    public static void main(String[] args) {
        test((List<BoundedI2<?>>) null);
        //test2((List<BoundedI2<?>>) null);
        test3((BoundedI2<?>) null);
    }

    public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }

    public static void test2(List<? extends Interface1<? extends Bound>> list) {}
    public static void test3(Interface1<? extends Bound> instance) {}
}
4b9b3361

Ответ 1

Похоже, что компилятор командной строки сталкивается с некоторыми трудностями при работе в режиме

  • тот факт, что BoundedI2 является общим для T, который должен быть "Связанным"
  • тот факт, что Interface2 расширяет интерфейс1

По крайней мере, без инстанцирования BoundedI2 правильно. Что действительно странно, так это то, что Eclipse, настроенный на одном JDK, компилирует его просто отлично... Обратите внимание, что Eclipse использует внутренний компилятор для обработки инкрементной перекомпоновки во время ввода, поэтому он вообще не вызывает компилятор JDK (см. Org/eclipse/jdt/internal/compiler).

Эта модификация позволяет скомпилировать ее как в Eclipse, так и в командной строке, заставляя BoundedI2 быть конкретным, а не по типу вывода:

import java.util.List;

public class PerfTest {
    interface Interface1<T> {}
    interface Interface2<T> extends Interface1<T> {}
    static class Bound {}
    interface BoundedI1<T extends Bound> extends Interface1<T> {}
    interface BoundedI2<T extends Bound> extends Interface2<T> {}
    static class Actual extends Bound {}

    public static void main(String[] args) {
        test((List<BoundedI2<Actual>>) null);
        test2((List<BoundedI2<Actual>>) null);
    }

    public static void test(List<? extends Interface2<? extends Bound>> list) { test2(list); }

    public static void test2(List<? extends Interface1<? extends Bound>> list) {}
}