W jaki sposób JLS określa, że ​​symboli wieloznacznych nie można formalnie używać w metodach?

Zawsze zastanawiałem się nad jakimś dziwnym aspektem generics Java i używaniem symboli wieloznacznych. Powiedzmy, że mam następujący interfejs API:

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

A następnie, powiedzmy, deklarujemy następujące metody:

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());
    }
}

Z mojego „intuicyjnego” zrozumieniaX<?> jest w rzeczywistości taki sam jakX<T>, z wyjątkiem tego, co nieznane<T> jestformalnie nieznany kodowi klienta. Ale w środkufoo(), Zgaduję, że kompilator może wywnioskować (pseudo kod JLS)<T0> := <?>[0], <T1> := <?>[1], etc.... To właśnie robi większość programistów w sposób jawny i intuicyjny. Przekazują prywatną metodę pomocniczą, co prowadzi do wielu niepotrzebnych kodów płyt kotłowych:

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

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

Inny przykład:

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());
    }
}

Innymi słowy, kompilator wie, że znak wieloznaczny jest wx.set() jest formalnie taki sam jak znak wieloznacznyx.get(). Dlaczego nie może wykorzystać tych informacji? Czy istnieje aspekt formalny wJLS, to wyjaśnia tę brakującą kompilator „funkcję”?

questionAnswers(3)

yourAnswerToTheQuestion