Java: problem with Generics & Collection type detection

I have a class called DataSet with different constructors, each of which defines a different type of variable. It might look something like this:

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. I have not had time to test this code yet due to incomplete parts (which I am currently creating).

In the function I'm currently creating, getDataObjects()

I need to return all DataObjects that this collection represents. In the case of constructors that initialize the HashSet class Data

with types other than DataObject

(for example, above ObjectRelationship

), obviously there will be no DataObjects stored internally. In this case, I need to define the type that the 'Data' HashSet was instantiated (for example, to determine "ObjectRelationship" or not, I mean). How should I do it?







tl; dr : how can I specify the type that the collection was created with (in this case, a HashSet) in my code (for example with an "if" or "switch" statement or whatever)?

0


source to share


8 answers


It sounds like you want to create a generic class - add a template parameter to the declaration for the class and define your HashSet and retrieval functions using that template parameter for types.

I'm a .Net guy at the moment, so I couldn't give you the Java syntax, but using C # syntax it would look something like this:



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;
    }
}

      

+4


source


You can get an object from a collection and check its type.

Or you can have multiple sets containing different types.



Or you could have an instance variable of type Class to act as a discriminator like an instance variable.

Or you can create a proxy object for the HashSet using the latter method.

+1


source


You can use the card to dial

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);

      

Then you get the best of both worlds.

+1


source


It looks like your design needs to be changed.

Also, to be clear to Generics; you cannot access the type at runtime. The type parameter is only for compile-time checking and disappeared completely (type erasure) at runtime.

+1


source


What does this class offer for CachedRowSet?

Sorry, I don't think this is a very good abstraction. If I was a member of your team, I would not use it.

Your syntax doesn't look correct to me. IntelliJ agrees with me: it won't compile.

This does:

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.
}

      

Still a bad abstraction. Rethink it.

0


source


You can add a property to your dataset class (enumerated value, boolean, or type) that specifies what type was used to initialize the hash.

Set the property in the appropriate constructor. This allows you to bypass getting an item from a collection to check its type.

pseudocode:

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


source


I'm going to follow duffymo's advice and just use the best abstraction. I'm going to make a few classes for each specific type that I plan to use (each one implements a common interface) so that I can just get around this dumb problem.

It will add a minor bit of overhead during the creation of each DataSet of the correct type, but I suppose this is the case.

0


source


I don't know what DataObject gives you over the Object.

I think an object oriented approach to your problem would use classes that reflect the domain of your interest (e.g. invoice, customer, etc.). The save level will keep the save details.

A common way to do this is to use a data access object, which might look like this in Java:

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

      

Now you are dealing with objects, not relational database stuff. All CRUD details are hidden behind the DAO interface.

0


source







All Articles