Toon posts:

[java 1.5] method met inner generic specifieker overriden

Pagina: 1
Acties:

Verwijderd

Topicstarter
o/,

Misschien een beetje een vage topic titel, maar ik weet niet hoe ik het anders in een paar woorden uit moet leggen :). Ik heb een Module class:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Module {
    
    public final List<Connector> getConnectors() {
        List joinedList = new ArrayList<Connector>();
        joinedList.addAll(this.getInputConnectors());
        joinedList.addAll(this.getOutputConnectors());
        return joinedList;
    }
    
    public abstract List<InputConnector<?>> getInputConnectors();
    public abstract List<OutputConnector<?>> getOutputConnectors();
    
    /**
     * @require getInputConnectors().contains(i)
     */
    public abstract void inputUpdate(InputConnector<?> i);
}

waarvan ik in de inheriting class AndModule de getInputConnectors() method wil implementeren met een specifiekere return type, namelijk public List<InputConnector<Boolean>>:
Java:
1
2
3
4
5
6
7
8
9
10
public class AndModule extends Module {
    protected List<InputConnector<Boolean>> inputConnectors;

    // cut
    public List<InputConnector<Boolean>> getInputConnectors() {
        return this.inputConnectors;
    }

    // cut
}

Iets dat zou moeten werken, zou je zeggen, aangezien InputConnector<Boolean> een subset is van InputConnector<?>. Zonder de List<> generic eromheen werkt het dan ook prima, maar zodra de InputConnector dus een inner generic wordt, werkt het niet meer. De foutmelding:
code:
1
2
3
getInputConnectors() in homecontrol.modules.stdlogic.AndModule cannot override getInputConnectors() in homecontrol.core.Module; attempting to use incompatible return type
found   : java.util.List<homecontrol.core.InputConnector<java.lang.Boolean>>
required: java.util.List<homecontrol.core.InputConnector<?>>


Nu heb ik het werkbaar gekregen met de volgende code:
Java:
1
2
3
4
    @SuppressWarnings("unchecked")
    public List<InputConnector<?>> getInputConnectors() {
        return (List)(this.inputConnectors);
    }

Maar
1) zo heeft de method specificatie van AndModule.getInputConnectors() niet aan dat er een lijst van Boolean InputConnectors wordt gereturned.
2) deze method implementatie komt een aantal keer voor (er zijn/komen ~30 module implementaties), en om nou 30 keer dit soort code te gebruiken :(.

Heeft er iemand suggesties :)?

  • PhoneTech
  • Registratie: Mei 2000
  • Laatst online: 19-02 16:25
Generics ondersteunen ook polymorphisme en in combinatie met interfaces kan dit erg krachtig zijn

Je kan dus ook List<? extends InputConnector> doen.

Verwijderd

Topicstarter
PhoneTech schreef op zaterdag 24 juni 2006 @ 14:34:
Generics ondersteunen ook polymorphisme en in combinatie met interfaces kan dit erg krachtig zijn

Je kan dus ook List<? extends InputConnector> doen.
Eh, ja, dus? Ik heb helemaal geen inheriting classes van InputConnector en op deze manier is de generic van InputConnector dus unspecified (1.4 style).

  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Wildcard types en niet-wildcard types zijn alleen gelijkwaardig als de wildcard op het hoogste niveau aanwezig is. Dus bijvoorbeeld dit werkt ook niet:
Java:
1
List<Bar<?>> bars = new ArrayList<Bar<Boolean>>();//fout

Dit heeft te maken met hoe wildcards de type-beperkingen beïnvloeden. Als het wel zou kunnen dan zou je door de generics beveiliging kunnen prikken. Een lijst met een concreet generic type (bijvoorbeeld Bar<?>) kun je wel elementen toevoegen (namelijk Bar<?> elementen). Bij een List<?> bijvoorbeeld kun je echter geen elementen meer toevoegen omdat de generic typedefinitie niet bepaald welke types de lijst kan bevatten. Daarom worden wildcards ook wel de "all-of-some-type" beperking genoemd.

Je zou in de abstracte klasse generic types op kunnen nemen die je in je concrete klasses gebruikt om de goede types aan te geven. Dit ziet er zo uit:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Bar<T> {
}

abstract class Foo<T> {
    abstract List<Bar<T>> getBars();
}

class FooBar extends Foo<Boolean> {
    @Override
    List<Bar<Boolean>> getBars() {
        // TODO Auto-generated method stub
        return null;
    }
}

[ Voor 8% gewijzigd door misfire op 24-06-2006 16:17 ]


  • Confusion
  • Registratie: April 2001
  • Laatst online: 01-03-2024

Confusion

Fallen from grace

Verwijderd schreef op zaterdag 24 juni 2006 @ 11:17:
Iets dat zou moeten werken, zou je zeggen, aangezien InputConnector een subset is van InputConnector.
Dat zou je denken, maar dat is niet zo. Een List<subclass-van-A> kan je ook niet (impliciet) naar List<A> casten, omdat dat zou betekenen dat je elementen A toe zou kunnen voegen, terwijl er later een methode op de lijst aangeroepen zou kunnen worden die specifiek voor subclass van A is. Als je dat weet, dan zou je weer op instanceof checks terug kunnen vallen, maar dat was nou net niet de bedoeling.
Heeft er iemand suggesties :)?
Module een generic type maken, waarbij de generic parameter de inner generic parameter van de InputConnector wordt. Blijkbaar hangt het return type van het moduletype af, dus op zich is dat gewoon netjes. Maar ergens klinkt het onlogisch, maar dat is afhankelijk van het verdere design.

[ Voor 4% gewijzigd door Confusion op 24-06-2006 16:58 ]

Wie trösten wir uns, die Mörder aller Mörder?


Verwijderd

Topicstarter
Bedankt voor de replies. Het probleem is alleen dat niet elke Module alleen InputConnectors van een bepaald type heeft. In sommige gevallen wel (AndModule, OrModule); in sommige gevallen niet (ComperatorModule).

Extra design info: Ik probeer een app te maken om een logische schakeling te bouwen, waar modules bepaalde in- en output connectors hebben die aan elkaar geknoopt kunnen worden. Zo zal een ComperatorModule twee InputConnector<Integer> hebben en een OutputConnector<Boolean>.

Ik zie inderdaad dat ik onduidelijk ben geweest in de TS, in dat ik voor de AndModule.getInputConnectors() method per se aan wil geven dat hier enkel Booleans uit komen; dit hoeft dus niet. Binnen de AndModule wil ik echter wel de inputConnectors object variabele opslaan als List<InputConnector<Boolean>>. Het "casten" van List<InputConnector<Boolean>> naar List<InputConnector<?>> kan echter helaas ook niet. Wat zou een goed alternatief design zijn hiervoor?

[ Voor 15% gewijzigd door Verwijderd op 24-06-2006 18:21 ]


  • misfire
  • Registratie: Maart 2001
  • Laatst online: 12-10-2024
Generics zijn alleen bedoeld om de exacte typedefinitie tijdens declaratie te kunnen beïnvloeden. Het verhaal over de verschillende soorten connectors klinkt op mij als iets wat je met polymorfisme zou willen oplossen. Probeer eens verschillende types te maken die één "Input/OutputConnector" interface implementeren. De interface zou methodes moeten hebben waar het gedrag in bepaald kan worden van de verschillende connectors. Op die manier houd je het onderscheid netjes binnen de connectors. Als je de specifiekere types toch graag in je module-interface wilt terugzien dan zijn wildcards soms wel handig (vanwege een andere handige Java 5 feature: co-variant return types):
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public abstract class Module {
    
    public final List<Connector> getConnectors() {
        List joinedList = new ArrayList<Connector>();
        joinedList.addAll(this.getInputConnectors());
        joinedList.addAll(this.getOutputConnectors());
        return joinedList;
    }
    
    public abstract List<? extends InputConnector> getInputConnectors();
    public abstract List<? extends OutputConnector> getOutputConnectors();
        
AndModule extends Module {
    protected List<BooleanInputConnector> inputConnectors;

    // cut
    public List<BooleanInputConnector> getInputConnectors() {
        return this.inputConnectors;
    }

    // cut
}

Subklasses van Module kunnen nu eventueel aangeven welke type connectors ze bevatten. Dit is een soort uitwerking van de eerste suggestie die PhoneTech ook gaf. :)
Confusion schreef op zaterdag 24 juni 2006 @ 16:57:
Dat zou je denken, maar dat is niet zo. Een List<subclass-van-A> kan je ook niet (impliciet) naar List<A> casten, omdat dat zou betekenen dat je elementen A toe zou kunnen voegen, terwijl er later een methode op de lijst aangeroepen zou kunnen worden die specifiek voor subclass van A is.
Om dit probleem op te lossen zijn juist wildcards bedacht. List<subclass-van-A> kun je wel converteren naar List<? extends A>. Dat is handig als je met verschillende soorten generic Lists wilt werken als je alleen elementen wil getten die aan A voldoen. Adden is verboden door de extends wildcard. Het probleem bij de TS is dat het type "InputConnector<?>" géén wildcard is, maar een type met een wildcard component.

[ Voor 14% gewijzigd door misfire op 24-06-2006 20:27 ]

Pagina: 1