-1

I need to use a collection of subclasses of basic class here is the description of the problem:

class A {
}

class B extends A{
}

class C extends A{
}

class D extends A{
}

I need to use a collection that I can get an instance of a subclass by its type only that mean when I need to get an instance of A class from the collection I need to get like this:

c.get(B.class);

If I have more than one instance from the same type I want to retrieve the instance by type and index: Examples: c.get(B.class, 0), c.get(B.class, 1), c.get(C.class)

Any help.

Ali Taha
  • 199
  • 1
  • 2
  • 16
  • the question is unclear. you say " use a collection of subclasses" . the collection holds the classes or instances of them? there is no API to get an item from a Java collection based on its type. can you provide more info on the usecase? – Sharon Ben Asher Feb 07 '19 at 09:57
  • 1
    You probably just have to filter your collection with checking in predicate that actual object is instanceof the type you need. https://stackoverflow.com/questions/122105/what-is-the-best-way-to-filter-a-java-collection – Serge Ageyev Feb 07 '19 at 09:57
  • @SharonBenAsher the collection should contain an instance of the subclasses, but I need to retrieve an instance by its type and index if there is more than one instance from the same type. – Ali Taha Feb 07 '19 at 10:03
  • You could write such a collection class. Or are you asking whether Java includes such a collection class? – Raedwald Feb 07 '19 at 12:36

3 Answers3

1

That would be best accomplished using Map and List

Map<Class, List<? extends A>> map = new HashMap<>()

You will then add element like this:

void addElement(final A element)
    if (!map.containsKey(element.getClass())){
        map.put(element.getClass(), new LinkedList<>());
    }    
    map.get(element.getClass()).add(element);
}

and you will be able to get n-th instance of particular class by

map.get(<Class here>).get(n);

I don't know of any implementation of a Collection, which would provide the convenient method get(key, index) so you will probably have to code it yourself.

NeplatnyUdaj
  • 6,052
  • 6
  • 43
  • 76
1

As noted in other answer, you can do it as Map, otherwise you can also extend a collection yourself - this sadly doesn't really allow you to use eg. List interface to call it, but it works if you use the class itself. It would look something like this:

class InstanceArrayList<T> extends ArrayList<T>
{
    public <V> V get(Class<V> instanceClass){
        return (V) this.stream()
            .filter( e -> e.getClass().equals( instanceClass ) )
            .findFirst()
            .orElse( null );
    }

    public <V> V get(Class<V> instanceClass, int index){
        return (V) this.stream()
            .filter( e -> e.getClass().equals( instanceClass ) )
            .skip( index ).findFirst()
            .orElse( null );
    }
}

It will warn you about unchecked cast - but we can ignore it safely, since we already know the object type matches.

And then you can just use it like this:

public static void main( String[] args )
    {
        InstanceArrayList<A> it = new InstanceArrayList<>();
        it.add( new A() );
        it.add( new A() );
        it.add( new B() );
        it.add( new B() );
        it.add( new C() );
        it.add( new C() );

        System.out.println(it.get( A.class ));
        System.out.println(it.get( A.class, 1 ));
        System.out.println(it.get( B.class ));
        System.out.println(it.get( B.class, 1 ));
        System.out.println(it.get( C.class ));
        System.out.println(it.get( C.class, 1 ));

    }

If you don't want it to return child class, you can also easly make it return T (superclass) instead.

Worthless
  • 531
  • 3
  • 7
0

It looks as if the thing you were looking for is Java's Map<K, V>. Shortly, it is a collection of key-value pairs. You can store values by invoking put(K, V) and access them by invoking V get(K) Most common implementation is HashMap. However, you won't be able to use Map<Class<T>, T>> as it will not give you an ability to store multiple values for a single key, so you solution would be storing collections of values as your map's values. For this you would require king of lazy initialization of the collection such as having map.computeIfAbsent(key, k -> new ArrayList<>()) for Map Map<Class<T>, Collection<T>>