wildcards bornées dans les types de référence

Huntro:

J'ai du mal à comprendre le code suivant sur les deux Predicateobjets. La première utilise un caractère générique borné inférieure, la seconde une partie supérieure délimitée.

Predicate<? super String> p1 = s -> s.startsWith("a"); // why can I call startsWith()?
Predicate<? extends String> p2 = s -> s.startsWith("a");

p1.test("a"); // works
p2.test("a"); // doesn't work (why?)

Ce que je ne comprends pas p1, pourquoi est - il possible d'appeler des méthodes de la classe String, par exemple startsWith()? Pourquoi ne puis - je passer que des Stringobjets dans p1.test(), je pensais pouvoir l' appeler pour Numberet des Objectobjets ainsi.

Comme p1se comporte , je pensais p2Plût, mais ce n'est pas le cas. Je ne peux pas passer même un Stringobjet dans p2.test(). Cela ne me paraît logique, parce que nous nous attendons à un objet qui hérite de String(y compris String).

Je pense qu'il a peut-être quelque chose à voir avec le fait que nous précisons le type de référence plutôt que le type de l'objet lui-même. Mais quel type est alors utilisé pour l'objet?

rgettman:

Il est légal pour vous d'appeler startsWithpour p1, même si p1est tapé avec une limite inférieure ? super String, parce que l'argument de type est déduit être String. L'expression lambda s -> s.startsWith("a");est déduit d'être Predicate<String>, ce qui est légal d'assigner à une variable de type Predicate<? super String>.

Cette compiles:

Predicate<String> ps = s -> s.startsWith("a");
Predicate<? super String> p1 = ps;

Cela ne signifie pas:

// no "startsWith" on Object
Predicate<? super String> p1 = (Object s) -> s.startsWith("a");

La référence de JLS est dans la section 15.27.3 , "type d'une expression lambda".

Si T est un type d'interface fonctionnelle paramétrés générique et l'expression lambda est typée implicitement, le type de cible au sol est la paramétrisation non générique (§9.9) de T.

Ici, le type de cible au sol est le type de l'expression lambda, et Test le type de cible, qui est ici votre type de données variable limite inférieure. Cela permet au compilateur d'assigner Predicate<String>comme type de cible au sol, qui devient le type de l'expression lambda.

Notez également que vous ne pouvez pas passer un objet à superclasse p1.test, parce que vous pouvez (et vous avez déjà) attribué un Predicate<String>à p1qui prend String.

p1.test(new Object()); // Error: can't pass something higher than String

Quant à savoir pourquoi vous ne pouvez pas passer un Stringà p2.test, lorsque vous avez un caractère générique supérieur bornés tels que ? extends String, cela signifie que le paramètre de type peut être une classe qui est soit Stringou un sous - type. (Le compilateur ignore qui Stringest - finallà et il ne peut y avoir de sous - classes String.) Le prédicat p2pourrait se voir attribuer une Predicate<SillyString>, en présumant SillyStringest une sous - classe String. Mais vous ne pouvez pas passer une Stringà une méthode qui pourrait s'attendre à un SillyString.

Je suppose que tu aimes

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