2008-12-26 7 views
0

J'ai une classe appelée DataSet avec différents constructeurs, chacun spécifiant un type de variable différent. Cela peut sembler un peu comme ceci:Java: Problème avec les génériques et la détection du type de collection

public class DataSet 
{ 
    private HashSet Data; 


    public DataSet(DataObject obj) 
    { 
     Data = new <DataObject>HashSet(); 
     Data.add(obj); 
    } 

    public DataSet(ObjectRelationship rel) 
    { 
     Data = new <ObjectRelationship>HashSet(); 
     Data.add(rel); 
    } 
    // etc. 

Note: Je ne l'ai pas encore appris à tester ce code en raison de pièces incomplètes (dont je suis la construction en ce moment).

Dans une fonction que je suis en train de construire, getDataObjects(), j'ai besoin de retourner tous les objets DataObject que cet ensemble représente. Dans le cas des constructeurs qui initient le HashSet de la classe, Data avec des types autres que DataObject (tels que ObjectRelationship ci-dessus), il n'y aura évidemment aucun DataObjects stocké dans. Dans ce cas, je dois être capable de détecter le type avec lequel le 'Data' HashSet a été initié (comme, pour dire si c'est 'ObjectRelationship' ou non, je veux dire). Comment puis-je faire cela?



tl; dr: Comment puis-je dire le type d'une collection (dans ce cas, un HashSet) a été lancé dans mon code (comme avec une déclaration 'si' ou 'switch' ou quelque chose)?

+0

Ne pas utiliser de génériques conduirait exactement au même problème. – Loki

+0

Il semble que vous mettez en place une sorte de collection. Peut-être que vous pourriez étudier le code source des autres classes de collecte pour avoir une idée de la façon d'atteindre votre objectif? – Loki

+0

Je ne fais qu'emballer HashSet pour faire quelque chose de spécifique avec ça. Ce n'est pas vraiment un nouveau type de collection, mais je suppose que je pourrais faire comme ça. Cependant, sa fonctionnalité sous le capot fonctionne différemment selon le type de données qui lui est donné. J'utilise seulement une poignée de types spécifiques, aussi. –

Répondre

1

Vous pouvez extraire un objet de l'ensemble et vérifier son type.

Ou vous pourriez avoir plusieurs ensembles pour contenir différents types.

Ou vous pouvez avoir une variable d'instance de type Class pour agir en tant que discriminateur en tant que variable d'instance.

Ou vous pouvez créer un objet proxy pour HashSet en utilisant la dernière technique.

0

Qu'est-ce que cette classe offre que CachedRowSet ne propose pas? Désolé, je ne considère pas que ce soit une très bonne abstraction. Si j'étais membre de votre équipe, je ne l'utiliserais pas.

Votre syntaxe ne me semble pas correcte non plus. IntelliJ est d'accord avec moi: il ne compilera pas.

Cela fait:

import java.util.HashSet; 
import java.util.Set; 
import java.util.Arrays; 

public class DataSet 
{ 
    private Set<DataObject> data; 


    public DataSet(DataObject obj) 
    { 
     this.data = new HashSet<DataObject>(); 
     data.add(obj); 
    } 

    public DataSet(DataObject[] objs) 
    { 
     data = new HashSet<DataObject>(); 
     data.addAll(Arrays.asList(objs)); 
    } 
    // etc. 
} 

Encore une abstraction pauvre. Repensez-y.

+0

Donc vous dites que je ne devrais pas initialiser avec plus d'un type? –

+0

Pour commencer, oui. Je dis aussi que toute la classe se sent mal à moi. – duffymo

+0

Et il ne compile pas simplement. Peut-être que c'est juste parce que c'était un exemple et non destiné à être représentatif de votre code exécutable. – duffymo

0

Vous pouvez ajouter une propriété à votre classe de dataset (une valeur énumérée, un booléen ou un type) qui spécifie quel type a été utilisé pour initialiser le hashset.

Définissez la propriété dans le constructeur approprié. Cela vous permet de contourner l'extraction d'un élément de la collection pour vérifier son type.

pseudo-code:

public class DataSet 
{ 
private HashSet Data; 
private Type _iw = null; 
public Type InitializedWith { return _iw; } 

public DataSet(DataObject) 
{ 
... 
_iw = typeof(DataObject); 
} 

public DataSet(ObjectRelationship) 
{ 
... 
_iw = typeof(ObjectRelationship) 
} 
+0

typeof? Je vais regarder dans ça. –

+0

je ne sais pas si cela existe en Java ou non, mais il y a sûrement quelque chose de similaire. Peut-être object.GetType()? – Jason

+0

Y at-il un typeof en Java? –

4

On dirait que vous voulez faire toute la classe generic- ajouter un paramètre de modèle à la déclaration de la classe et de définir votre HashSet et les fonctions de récupération en utilisant ce paramètre de modèle pour les types .

Je suis un.guy net au moment, cependant, donc je ne saurais vous donner la syntaxe Java, mais en utilisant C# syntaxe il ressemblerait à quelque chose comme ceci:

public class DataSet<T> 
{ 
    private Set<T> Data; 

    public DataSet(T obj) 
    { 
     Data = new HashSet<T>(); 
     Data.add(obj); 
    } 

    public Iterator<T> getDataObjects() 
    { 
     return Data.iterator; 
    } 
} 
+0

Mais j'ai encore besoin de connaître le type spécifique pour mon code (comme dans, pour une déclaration 'if' ou 'switch' ou quelque chose pour être en mesure de vérifier). –

+0

Non: vous êtes le type de retour dans cette fonction est juste "T": votre type de modèle. –

+0

Même pour Java que ce code. Très bien, mais toujours pas ce que je recommanderais. – duffymo

0

Je vais suivre les conseils de duffymo et il suffit d'utiliser meilleure abstraction. Je vais créer plusieurs classes pour chaque type spécifique que je prévois d'utiliser (chacune implémentant une interface commune) afin que je puisse contourner ce problème stupide.

Il va ajouter un minuscule peu de surcharge au cours du processus de création de chaque objet DataSet du type correct, mais je suppose que c'est comme ça que ça se passe.

1

Vous pouvez utiliser une carte pour l'ensemble

HashMap <Class<?>, HashSet<Object>> data; 
HashSet temp = data.get(DataObject.class); 
if(temp == null) 
{ 
    temp = new HashSet(); 
    data.put(DataObject.class, temp); 
} 
temp.add(obj); 

Ensuite, vous obtiendrez le meilleur des deux mondes.

+0

Clever, mais ce n'est pas exactement ce dont j'ai besoin. Pourtant, je pourrais probablement utiliser cette technique pour plus tard ... –

0

Je ne sais pas ce que DataObject vous donne au-dessus et au-dessus d'un objet.

Je pense qu'une approche orientée objet de votre problème utiliserait des classes qui reflètent votre domaine d'intérêt (par exemple, facture, client, etc.). La couche de persistance masquerait les détails de persistance.

Une façon courante d'y arriver est d'utiliser l'objet d'accès aux données, ce qui pourrait ressembler à ceci en Java:

public interface GenericDao<T> 
{ 
    T find(Serializable id); 
    List<T> find(); 
    void save(T obj); 
    void update(T obj); 
    void delete(T obj); 
} 

Maintenant, vous avez affaire à des objets plutôt que de choses qui claquent des bases de données relationnelles. Tous les détails de CRUD sont cachés derrière l'interface DAO.

1

On dirait que votre design doit être repensé.

Également, pour être clair sur les génériques; vous ne pouvez pas accéder au type lors de l'exécution. Le paramètre type est uniquement pour la vérification lors de la compilation et a complètement disparu (effacement de type) lors de l'exécution.

Questions connexes