Is het mogelijk om twee jokertypes van hetzelfde type te verklaren?

Ik wil een toewijzing maken van (a) klassetype naar (b) lang (de identifier van het object van het gedefinieerde klassentype) naar (c) het object zelf.

Ik heb het volgende:

 protected HashMap obj = new HashMap();

Is het mogelijk om op de een of andere manier aan te geven dat de eerste ? van hetzelfde type moet zijn als de tweede ? ? Ik zou zoiets verwachten, maar dit is natuurlijk niet mogelijk:

protected  HashMap, HashMap> obj = new HashMap, HashMap>();
4
U kunt veel van hetzelfde bereiken door uw oorspronkelijke definitie te gebruiken met de onbegrensde jokertekens en items toe te voegen/op te halen van de kaart met behulp van generieke methoden die uw beperking afdwingen. Deze zouden niet helemaal veilig zijn, maar een goed ingekapselde, onveilige code is waarschijnlijk acceptabel.
toegevoegd de auteur millimoose, de bron
Je ziet het verkeerd. kan van elk type zijn, maar alle exemplaren van T moeten van hetzelfde type zijn.
toegevoegd de auteur Nate W., de bron
U moet die typedefinitie toevoegen aan de omsluitende klasse of methode die de HashMap gebruikt.
toegevoegd de auteur Nate W., de bron
heel interessant punt, maar ik denk niet dat je zo'n beperking helaas kunt opbouwen.
toegevoegd de auteur aishwarya, de bron
Ik denk dat ik het niet kan. Ik verzamel/caching van een reeks klassen in mijn kaart. Niet één. Het kan van elk type zijn. Of zie ik het verkeerd?
toegevoegd de auteur Japer D., de bron

4 antwoord

Als alternatief kunt u een kleine hoeveelheid niet-type-veilige code gebruiken die is ingekapseld op een manier die uw beperking afdwingt:

class Cache {
    private Map items = new HashMap();

    private  Map getItems(Class type) {
        @SuppressWarnings("unchecked")
        Map result = (Map) items.get(type);
        if (result == null) {
            result = new HashMap();
            items.put(type, result);
        }
        return (Map) result;
    }

    public  void addItem(Class type, Long id, T item) {
        getItems(type).put(id, item);
    }

    public  T getItem(Class type, Long id) {
        return type.cast(getItems(type).get(id));
    }
}

De type.cast() in getItem() is niet nodig voor de compiler om niet te klagen, maar het zou helpen om een ​​object van het verkeerde type te vangen dat in de cache komt vroeg.

5
toegevoegd
goede oplossing en dit zou de truc kunnen doen voor alle praktische doeleinden!
toegevoegd de auteur aishwarya, de bron
Bedankt. Dit is heel logisch. Voor de buitenwereld is alles veilig getypt. Voor de implementatie wordt een 'veilige cast' gebruikt.
toegevoegd de auteur Japer D., de bron
Tussen haakjes, u vermeldt dat .cast() wordt uitgevoerd voordat u het in de cache plaatst. In je codefragment cast je nadat je het uit de cache hebt opgehaald.
toegevoegd de auteur Japer D., de bron

Elk voorkomen van een joker komt overeen met een ander type en de enige geschikte scope voor een typeparameter die het type vertegenwoordigt, is de invoer in de buitenste HashMap. Helaas staat HashMap het toelaten van het boekingstype in zijn type-parameter, zoals:

class Entry {
   //fields omitted
}

class Map extends Entry, Map>> { }

class EntityCache extends Map { }

Zelfs als dat zo is, is er geen manier om Map.get te implementeren zonder ongecontroleerde casts te gebruiken, omdat we de parameter type moeten beperken tot een bepaald lid van het type gezin dat wordt vertegenwoordigd door E - en u kunt een typeparameter van een typeparameter in Java niet beperken.

Daarom is je enige verhaal het schrijven van een gevel waarvan api het type invariant afdwingt, maar intern afgietsels gebruikt:

class EntityCache {
    Map> map = new HashMap<>();

    public  void put(Class clazz, long id, E entity) {
        map.get(clazz).put(id, entity);
       //TODO create map if it doesn't exist yet
    }

    public  E get(Class clazz, long id) {
        return clazz.cast(map.get(clazz).get(id));
       //TODO what if not found?
    }
}
2
toegevoegd
1. Bedankt voor je antwoord. Dit is min of meer dezelfde aanpak als die van Inerdial.
toegevoegd de auteur Japer D., de bron

What you probably want is: HashMap>. Because you will be putting objects of different types in it, Object is the type parameter that will allow you to add any type of object.

Raak niet verward met het jokerteken (? ). Het heeft de tegenovergestelde betekenis - het betekent dat de parameter een bepaald type is (dus alle objecten moeten van dat type zijn) maar we weten niet wat het is, dus kunnen we er niets in doen. Dat is niet wat je wilt.

0
toegevoegd
Dit zou je waarschijnlijk moeten lezen. Laten we zeggen dat je een verwijzing hebt naar type Lijst <?> ; het zou kunnen verwijzen naar een object van het type Lijst of Lijst of Lijst . Als het een object van het type Lijst was, kunt u er geen integer s aan toevoegen. Met andere woorden, <?> betekent dat er een bepaalde type parameter is (dus alle elementen moeten van dat type zijn) maar we weten niet wat die parameter is; dus we kunnen er veilig niets aan toevoegen. Aan de andere kant kun je er met een Lijst iets aan toevoegen.
toegevoegd de auteur newacct, de bron
Ik heb echt problemen om te begrijpen waarom <?> Niet gelijk is aan . Niet '?' betekent 'iets', wat een object is? Wil je dat ik hier een nieuw onderwerp voor maak?
toegevoegd de auteur Japer D., de bron

You could extend the HashMap class with your specific generic definitions and make a generic class that takes the as argument, something like this:

public class MyHashMap extends HashMap, HashMap> { ...
0
toegevoegd
Maar, volgens de opmerking van de OP over de vraag, wil hij dat de kaartsleutels Class -objecten zijn voor verschillende typen. Een HashMap ,?> zou volledig nutteloos zijn omdat er toch maar één exemplaar van het type Class in een JVM zit. (Behoudens het gebruik van de Classloader dat niet relevant is in de meeste applicaties.)
toegevoegd de auteur millimoose, de bron
Als ik de vraag goed begrijp, wil hij dat de kaart de volgende inhoud heeft: {Foo.class => Kaart , Bar.class => Kaart }
toegevoegd de auteur millimoose, de bron
Dit is niet waar het OP om vroeg. (Wat het OP vroeg, is hoe dan ook onmogelijk.)
toegevoegd de auteur millimoose, de bron
Sorry als ik me in het begin niet duidelijk heb gemaakt. Ik waardeer de feedback, ik vind het een goed idee als ik slechts één type nodig heb. Bedankt.
toegevoegd de auteur Japer D., de bron
Waarom? Als hij dit doet en vervolgens zijn object instantieert met het nieuwe type, zal het afdwingen dat beide generieke types in de HashMap-definitie hetzelfde zijn, wat de OP wil.
toegevoegd de auteur olex, de bron
Ja, en je zou precies dat kunnen bereiken: MyHashMap obj = nieuwe MyHashMap () zou een uitgebreide zijn HashMap , HashMap > .
toegevoegd de auteur olex, de bron
Inderdaad, je hebt gelijk ... Ik realiseerde me niet dat deze implementatie de hele kaart zou beperken tot één sleutelklasse en dus één enkele sleutel. Bedankt voor de geduldige uitleg :)
toegevoegd de auteur olex, de bron