Generyczna zagwozdka

2

Pytania za 100 punktów: czemu to się kompiluje:

class Generic <T>  { // tu się różni
    private List<Number> numbers;

    public void setNumbers(List<Number> numbers) {
        this.numbers = numbers;
    }
}

class Service<U extends Generic> {

    public List<? extends Number> produce() {
        return new LinkedList<>();
    }

    public void process(U generic) {
        generic.setNumbers(produce());
    }
}

a to nie:

class Generic   { // tu się różni
    private List<Number> numbers;

    public void setNumbers(List<Number> numbers) {
        this.numbers = numbers;
    }
}

class Service<U extends Generic> {

    public List<? extends Number> produce() {
        return new LinkedList<>();
    }

    public void process(U generic) {
        generic.setNumbers(produce());
    }
}

Błąd kompilacji raczej oczywisty:

 method setNumbers in class Generic cannot be applied to given types;
        generic.setNumbers(produce());
               ^
  required: List<Number>
  found: List<CAP#1>
  reason: argument mismatch; List<CAP#1> cannot be converted to List<Number>
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Number from capture of ? extends Number
1 error

Pytanie jest bardziej o to, czemu wprowadzenie nieużywanego typu parametryzującego klasę Generic wyłącza kontrolę typów?

0

Zgaduje: U extends Generic -> Robisz rawtype z tego bo Generic byl generyczny, co sprawia że U jest rawtype więc twoje U generic jest rawtype i typy generyczne są na nim wymazane.
Wystatrczy że w tym pierwszym dasz class Service<U extends Generic<COŚTAM>> { i już będziesz miał taki sam efekt jak niżej.

4

Z JLS (https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.8):

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

Tak jak napisał @Shalom - w pierwszym przypadku U staje się raw typem, gdzie wszystkie type parameters są wymazywane, nawet te podane "explicite" i niezwiązane z type parametrem klasy. Dlatego wtedy się kompiluje, bo metoda setNumbers staje się metodą przyjmującą gołe List

0

Dzięki za obie odpowiedzi. Kurcze, 4 lata w javie kodze i dziś pierwszy raz na taki przypadek trafiłem. Robiłem dość głęboki refactoring firmowego frameworka i zacząłem porządkować spaprane generyki. Po uporządkowaniu kod się przestał kompilować. Wynika z tego, że tam kontrola typów nie działała od co najmniej roku. Intellij nie pokazuje mi w tym przypadku warninga choć podczas ręcznej kompilacji ostrzeżenie o unchecked types jest.

0

Intellij nie pokazuje mi w tym przypadku warninga choć podczas ręcznej kompilacji ostrzeżenie o unchecked types jest.

To chyba tak sobie ustawiłeś, bo mi na defaultach zaznacza o razu że w U extends Generic Generic jest rawtype i pokazuje warning.

1 użytkowników online, w tym zalogowanych: 0, gości: 1