Diamond in Generics Java 1.7 - hoe schrijf ik dit voor Java Compiler in 1.6

hoe kan ik Java 1.7-code schrijven voor een Java 1.6-compiler, waarbij de diamant niet kan worden gebruikt?

Voorbeeld:

private ReplacableTree convertToIntended(Tree<? extends E> from,ReplacableTree to) {

    TreeIterator<? extends E> it = new TreeIterator<>(from.getRoot());

    while(it.hasNext()) {
        E e = it.next().getElem();
        to.add(e);
    }
    return to;
}


public class TreeIterator implements TreeIter> {
....
}

Het is niet toegestaan ​​om te schrijven ...

TreeIterator<? extends E> it = new TreeIterator<?>(from.getRoot());
TreeIterator<? extends E> it = new TreeIterator(from.getRoot());
TreeIterator<? extends E> it = new TreeIterator<? extends E>(from.getRoot());

Vooral de derde is verwarrend voor mij. Waarom werkt het niet? Ik wil alleen Elements from a Tree (dat een subtype boom zou kunnen zijn) lezen, en wanneer ik er elk van een in een nieuwe Tree met Elements van type E.

1
De derde is niet syntactisch correct. (Plaats geen antwoorden in reacties.). Ik stop de vraag over de handtekeningen van getRoot() en de TreeIterator constructor.
toegevoegd de auteur meriton, de bron
getRoot (): Node <? breidt E uit> zegt eclipse In code: openbare abstracte klasse Boom {beschermd knooppunt root;//het rootelement van de boom/** * @return Retourneert een element van Type E als referentie. */public Node getRoot() {return root; }}
toegevoegd de auteur Blackbam, de bron
En de Tree Iterator Constructor: TreeIterator (knooppunt knooppunt) {this.head = knooppunt; this.current = head; start = false; }
toegevoegd de auteur Blackbam, de bron
De derde is syntactisch correct, maar ik kan niet achterhalen wat het probleem is zonder de handtekening van getRoot() en de constructor TreeIterator .
toegevoegd de auteur millimoose, de bron
@meriton Oh, je kunt geen jokertekens gebruiken bij het instantiëren van objecten.
toegevoegd de auteur millimoose, de bron
@Blackbam: nu mist het de definitie van Node. Kunt u alstublieft alles opgeven wat nodig is om alle code (behalve de problematische regel) te compileren? En je zou je vraag moeten bewerken, plaats alsjeblieft geen grotere stukjes code in reacties.
toegevoegd de auteur millimoose, de bron

5 antwoord

Jokertypes zijn niet toegestaan ​​als typeargumenten in expressiebewerkingen voor klasseninstanties :

Het is een compileerfout als een van de typeargumenten die worden gebruikt in een expressie voor een creatie van een klasse-instantie, jokertype-argumenten zijn (§4.5.1).

dus de eerste en derde varianten zijn niet geldig.

Variant 2 is invalid because the TreeIterator constructor wants a Node, but you give it a Node<? extends E>.

Wat de oplossing betreft, Java 5 en 6 hadden geen type-gevolgtrekking voor constructeurs, maar hebben wel een type-gevolgtrekking voor methoden, en in het bijzonder vastleggen van conversie . Het volgende zou moeten compileren:

TreeIterator<? extends E> it = makeIterator(from.getRoot());

waar

private  TreeIterator makeIterator(Node node) {
    return new TreeIterator(node);
}

Edit: You asked in the comment:

The contstructor parameter type for TreeIterator is Node. The constructor parameter of Node therefore is E. When writing variant two, eclipse says the following: The constructor TreeIterator(Node ) is undefined What does that mean?

Being a wildcard type, the type Node<? extends E> represents a family of types. Node refers to a specific type in that family. That distinction is irrelevant in this case. What matters is that Node<? extends E> is not a subtype of Node, and hence you can't pass an instance of Node<? extends E> to a constructor expecting a Node.

4
toegevoegd
Het parametertype contructionor voor TreeIterator is Knooppunt . De constructorparameter van knooppunt is daarom E. Bij het schrijven van variant twee zegt verduistering het volgende: De constructor TreeIterator (knooppunt ) is undefined Wat betekent dat?
toegevoegd de auteur Blackbam, de bron

Kortom, je schrijft geen Java 7-code voor een Java 6-compiler - je moet de oude, duplicatieve niet-diamantsyntaxis gebruiken. En nee, je kunt een doel van 1.6 niet specificeren met bron 1.7, het zal niet werken!

1
toegevoegd

Usually, <> means to just use the same type parameter as in the declaration to the left. But in this case, that declaration is a wildcard.

It doesn't make sense to make a constructor with a wildcard type parameter, new TreeIterator<? extends E>(...) because, usually, if you don't care what parameter to use, you should just pick any type that satisfies that bound; which could be E, or any subtype thereof.

However, in this case, that doesn't work because the constructor of TreeIterator takes an object with the type parameter . You didn't show the source code of TreeIterator, so I can't see what it does, but chances are that its bound is too strict. It could probably be refactored to make the type parameter <? extends E>.

Maar er zijn enkele gevallen waarin dat niet mogelijk is. In een dergelijk geval kunt u nog steeds de noodzaak van de typeparameter E elimineren via een "capture-helper" (wat meriton hierboven suggereert) om iets te draaien dat parameter E inneemt iets dat een joker nodig heeft? breidt E uit.

1
toegevoegd

meriton legde het al goed uit. Ik wil alleen maar voorstellen dat je het net zo goed kunt doen zonder de wildcard-verklaring:

TreeIterator it = new TreeIterator(from.getRoot());
1
toegevoegd
Dat zou nodig zijn om de methodesignatuur van convertToIntended te veranderen om uit te declareren als type Tree . We weten niet of de bellers daarna nog zouden compileren.
toegevoegd de auteur meriton, de bron
Het verschil is dat de constructor van ArrayList zijn argument als van het type Verzameling uit. Het zou niet werken als het aangegeven type Verzameling was. De constructor van TreeIterator verklaart het argument van het type knooppunt , niet knooppunt <? breidt E> uit.
toegevoegd de auteur meriton, de bron
@meriton: Waarom denk je dat het een verandering van de handtekening zou vereisen? Ik heb zojuist een eenvoudig voorbeeld geprobeerd dat dezelfde conversie alleen met verschillende klassen uitvoert klasse Test {Lijst -test (Verzameling <? Breidt E uit van) {return new ArrayList (from); }} en het compileert goed in Java 1.6.
toegevoegd de auteur x4u, de bron

Ik weet dat dit een oude vraag is, maar voor het geval iemand hier tegenaan loopt, zou ik gedacht hebben dat de meest voor de hand liggende manier om te schrijven het zou zijn geweest:

private  ReplaceableTree convertToIntended(Tree from, ReplaceableTree to)
{
    TreeIterator it = new TreeIterator(from.getRoot());

    while(it.hasNext())
    {
        E e = it.next().getElem();
        to.add(e);
    }

    return to;
}

Ik denk niet dat een dergelijke wijziging bestaande code zou doorbreken, aangezien de typebeperkingen hetzelfde zijn van de bestaande handtekening tot deze.

0
toegevoegd