Como o JLS especifica que os curingas não podem ser formalmente usados ​​nos métodos?

Eu sempre estive pensando sobre algum aspecto estranho dos genéricos Java e o uso de curingas. Digamos que eu tenha a seguinte API:

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

E então, digamos que declaramos os seguintes métodos:

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

Do meu entendimento "intuitivo",X<?> é de fato o mesmo queX<T>, exceto que o desconhecido<T> éformalmente desconhecido para o código do cliente. Mas dentro defoo(), Eu diria que o compilador poderia inferir (pseudo código JLS)<T0> := <?>[0], <T1> := <?>[1], etc.... Isso é o que a maioria dos programadores faz de forma explícita e intuitiva. Eles delegam a um método auxiliar privado, o que leva a muitos códigos inúteis de placa de caldeira:

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

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

Outro exemplo:

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

Em outras palavras, o compilador sabe que o curinga emx.set() é formalmente o mesmo que o curinga emx.get(). Por que não pode usar essa informação? Existe um aspecto formal noJLS, isso explica esse "recurso" do compilador que está faltando?

questionAnswers(3)

yourAnswerToTheQuestion