8
votes

Java Ajouter une liste de classe spécifique à la liste des œuvres Java.Lang.Object avec Java 8 Streams - Pourquoi? Pourquoi?

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?

2 commentaires

SETLISTA (COLLECTIONS.UNMODIFIALIST (LISTB)) Travaillerait également sans la surcharge de la création d'un flux.


@Radiodef qui ferait quelque chose qui est complètement différent du code posté. (Non liée à l'inférence de type, etc., mais je voulais le mentionner. Passer dans un Nouvelle ArrayList (listb) serait plus proche de ce que le code affiché fonctionne et fonctionnait aussi bien)


3 Réponses :


8
votes

Pour le premier cas, il échoue car list code> n'est pas un sous-type de la liste code>. 1 sup>

Pour le second cas, nous avons les déclarations de méthode suivantes: p> xxx pré>

et: p> xxx pré>

ceci permet à Java de déduire le Paramètres de type générique du contexte. 2 sup> dans ce cas list code> est déduit pour r code> et objet code> Pour t code>. p>

Ainsi, votre code est équivalent à celui-ci: P>

Collector<Object, ?, List<Object>> tmpCollector = Collectors.toList();
List<Object> tmpList = listB.stream().collect(tmpCollector);
setListA(tmpList);


7 commentaires

Cela signifie-t-il alors que le problème est une extinction implicite à objet dans le premier cas "ne fonctionne pas"?


@THOMAS - C'est simplement que Liste n'est pas un sous-type de la liste , et donc l'affectation échoue.


Pouvez-vous expliquer plus en détail pourquoi la liste est déduite pour r et objet pour t? Surtout dans le contexte que listb.stream () retourne réellement un flux , alors pourquoi listb.stream (). Recueillir (...) 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 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 est list de setlista et le type cible de tolist est Collectionneur de collect . Je pense que Javac doit concerner le type de collecter 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 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)); qui fonctionne également depuis Java 8. Dans les versions Java plus anciennes, SetLista ( Nouvelle ArrayList (listb)); serait requis.



2
votes

Cette ligne xxx

ne fonctionne pas car list dans java est invariant, signification list "T étend list lorsque testclass étend objet . Plus de détails ici < p> cette ligne xxx

fonctionne car Java Inférer objet pour le type générique de collecteur de cette méthode Signature setlista (liste finale liste) Vous passez en fait list


1 commentaires

J'aime votre explication de l'invariance dans ce cas. Je me demandais réellement à ce sujet, merci.



1
votes

Les paramètres de type de Java Generic sont invariance forts> ce qui signifie qu'il ne peut être hérité de la hiérarchie de la classe Paramètres de type. Le parent commun de la liste code> et list code> est list > Code>.

héritage générique p>

Vous pouvez voir détaillé Réponse sur Java Generic Wildcard de KOTLIN & Java . Par exemple: P>

List<?> listA = new ArrayList<>();

private static void setListA(List<?> list) {
    listA = list;
}


0 commentaires