Как JLS определяет, что подстановочные знаки не могут быть формально использованы внутри методов?

Я всегда интересовался каким-то странным аспектом обобщений Java и использованием подстановочных знаков. Допустим, у меня есть следующий API:

public interface X<E> {
    E get();
    E set(E e);
}

А затем, скажем, мы объявили следующие методы:

public class Foo {
    public void foo(X<?> x) {
        // This does not compile:
        x.set(x.get());
    }

    public <T> void bar(X<T> x) {
        // This compiles:
        x.set(x.get());
    }
}

Из моего & quot; интуитивного & quot; понимание,X<?> на самом деле так же, какX<T>разве что неизвестно<T> являетсяformally неизвестный клиенту код. Но внутриfoo()Я бы предположил, что компилятор может сделать вывод (псевдо-JLS-код)<T0> := <?>[0], <T1> := <?>[1], etc..., Это то, что большинство программистов делают явно и интуитивно. Они делегируют частному вспомогательному методу, который приводит к большому количеству бесполезного кода котельной пластины:

public class Foo {
    public void foo(X<?> x) {
        foo0(x);
    }

    private <T> void foo0(X<T> x) {
        x.set(x.get());
    }
}

Другой пример:

public class Foo {
    public void foo() {
        // Assuming I could instanciate X
        X<?> x = new X<Object>();
        // Here, I cannot simply add a generic type to foo():
        // I have no choice but to introduce a useless foo0() helper method
        x.set(x.get());
    }
}

Другими словами, компилятор знает, что подстановочный знак вx.set() формально такой же, как подстановочный знак вx.get(), Почему он не может использовать эту информацию? Есть ли формальный аспект вJLS, что объясняет отсутствие функции компилятора?

Ответы на вопрос(3)

Ваш ответ на вопрос