public class Test { static List<Object> listA = new ArrayList<>(); public static void main(final String[] args) { final List<TestClass> listB = new ArrayList<>(); listB.add(new TestClass()); // not working setListA(listB); // working setListA(listB.stream().collect(Collectors.toList())); System.out.println(); } private static void setListA(final List<Object> list) { listA = list; } } why does it work with streams and does not work for the simple set?
3 Réponses :
Pour le premier cas, il échoue car Pour le second cas, nous avons les déclarations de méthode suivantes: p> et: p> ceci permet à Java de déduire le Paramètres de type générique du contexte. 2 sup> dans ce cas Ainsi, votre code est équivalent à celui-ci: P> list
list
r code> et
objet code> Pour
t code>. p>
Collector<Object, ?, List<Object>> tmpCollector = Collectors.toList();
List<Object> tmpList = listB.stream().collect(tmpCollector);
setListA(tmpList);
Cela signifie-t-il alors que le problème est une extinction implicite à objet code> dans le premier cas "ne fonctionne pas"?
@THOMAS - C'est simplement que Liste
Pouvez-vous expliquer plus en détail pourquoi la liste listb.stream () code> retourne réellement un
flux
listb.stream (). Recueillir (...) code> Utiliser l'objet à la place?
@Klitoskyracou - Les règles sont complexes et je ne prétends pas les comprendre assez bien pour pouvoir les expliquer sans ambiguïté. Voir angélikalanger.com/genericsfaq/javagenericsfaq.html pour une meilleure explication que je ne pourrais jamais donner!
@Olivercharlesworth ayant été enseignant, moi-même, j'apprécie toujours un ingénieur clairement compétent en disant "je ne sais pas." C'est une chose importante et je souhaite que plus de personnes dans notre monde l'ont fait.
@Klitoskyracou Type Inference utilise quelque chose appelé le type de cible i> d'une expression. Pour une expression d'invocation de méthode, le type cible est généralement quelle que soit la valeur de retour, dans ce cas, un paramètre d'une autre méthode. Le type de cible de collecter code> est
list
setlista code> et le type cible de
tolist code> est
Collectionneur Super t, a, r> code> de
collect code>. Je pense que Javac doit concerner le type de
collecter code> d'abord ici, basé sur le fait que ce code compile, mais cela fait un certain temps depuis que j'ai lu cette section de la JLS.
@Radiodef: Votre exemple en utilisant UNDODIFIALLELIST code>
serait un point de départ plus simple lorsque vous essayez d'expliquer l'inférence de type cible. L'approche de collection de flux / tolistes crée une copie, ce qui équivaut à setlista (nouvelle arrayliste <> (listb)); code> qui fonctionne également depuis Java 8. Dans les versions Java plus anciennes,
SetLista ( Nouvelle ArrayList
Cette ligne ne fonctionne pas car fonctionne car Java Inférer objet pour le type générique de collecteur de cette méthode Signature list code> dans java est invariant, signification
list
list
testclass code> étend
objet code>. Plus de détails ici P> < p> cette ligne p>
setlista (liste finale
list
J'aime votre explication de l'invariance dans ce cas. Je me demandais réellement à ce sujet, merci.
Les paramètres de type de Java Generic sont p> Vous pouvez voir détaillé Réponse sur Java Generic Wildcard de KOTLIN & Java . Par exemple: P>
list
list > Code>.
List<?> listA = new ArrayList<>();
private static void setListA(List<?> list) {
listA = list;
}
SETLISTA (COLLECTIONS.UNMODIFIALIST (LISTB)) CODE> Travaillerait également sans la surcharge de la création d'un flux.
@Radiodef qui ferait quelque chose qui est complètement différent i> du code posté. (Non liée à l'inférence de type, etc., mais je voulais le mentionner. Passer dans un
Nouvelle ArrayList (listb) code> serait plus proche de ce que le code affiché fonctionne et fonctionnait aussi bien)