Types incompatibles lors de l'utilisation des génériques récursives en Java

Niels Basjes:

J'ai écrit code java où j'utilise une forme récurrente de médicaments génériques pour obtenir une manière propre de faire un modèle constructeur héritable.

Cela fonctionne, mais je ne comprends pas certains des avertissements et des erreurs que je reçois du compilateur java.

Ceci est la version simplifiée sérieusement de la partie, je ne comprends pas:

package nl.basjes.test;

public class Foo<X extends Foo<X>> {
  public X doSomething() {
    return this;
  }
}

Pour le "return this;" Je reçois l'erreur

Incompatible Types
Required: X
Found   : nl.basjes.test.Foo <X>

Maintenant , « ce » est toujours une sous - classe de Foo (ou même Foo lui - même) et « X » est défini comme X extends Foo<X>. À ma connaissance , ceux - ci devraient être « les mêmes » , mais apparemment , ils ne sont pas.

Donc, dans mon code, j'ai ajouté un casting à la déclaration de retour comme ceci:

package nl.basjes.test;

public class Foo<X extends Foo<X>> {
  public X doSomething() {
    return (X)this;
  }
}

ce qui rend la compilation de code et le travail comme prévu et prévu.

Cependant, je ne reçois toujours un avertissement sur « cast non contrôlé » pour la même raison que ci-dessus (mais maintenant il est juste un avertissement).

$ javac -Xlint:unchecked nl/basjes/test/Foo.java 
nl/basjes/test/Foo.java:5: warning: [unchecked] unchecked cast
        return (X)this;
                  ^
  required: X
  found:    Foo<X>
  where X is a type-variable:
    X extends Foo<X> declared in class Foo
1 warning

Pourquoi ne pas Java voir que X(qui étend Foo<X>) et this(qui étend Foo<X>) sont compatibles?

A ce stade, ma meilleure estimation est que cela a à voir avec une partie de l'effacement de type que je ne comprends pas encore.

ernest_k:

Lorsque l'on considère les arguments de type béton, il devient plus facile de voir le problème:

Supposer

Foo<Bar> barFoo = ...;

Lorsque vous appelez barFoo.doSomething(), vous vous attendez à obtenir un Barobjet:

Bar bar = barFoo.doSomething()

Cependant, votre mise en œuvre effective:

public X doSomething() {
  return this;
}

Peut être rempli à peu près avec les paramètres concrets suivants:

public Bar doSomething() {
  return this; //But "this" is a Foo<Bar>, not a Bar.
}

Voici un autre exemple pour le rendre encore plus évident:

class Bar extends Foo<Bar> {
}
class Baz extends Foo<Bar> { //note this is a Foo<Bar>
}

Et:

Baz baz = new Baz();
Bar bar = baz.doSomething();

Dans ce qui précède, vous vous attendez baz.doSomething()à retourner un Bar, mais le code doSomething()renvoie une Baz, mais la coulée à Bar, qui a un problème de sécurité de type (en fait, ces types sont incompatibles, mais vous obtenez seulement un ClassCastException quand vous avez différentes classes comme dans le dernier exemple).

Je suppose que tu aimes

Origine http://43.154.161.224:23101/article/api/json?id=202607&siteId=1
conseillé
Classement