Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining the type of objects in a collection or array

Suppose I have an array int[][] or an array char[][] or an ArrayList. Is there a way in java to know the base class type of the array. For Example:

int[][] gives output as int.
char[][] gives output as char.
ArrayList<Integer> gives output Integer.
ArrayList<Point> gives Point. (It should also work for a custom type)

Can this be done in Java?

like image 720
Rishi Avatar asked Jul 12 '13 05:07

Rishi


2 Answers

Arrays (e.g. int[][])

You can get the array's component type using getComponentType():

(new int[10][10]).getClass().getComponentType().getComponentType(); // int

For arrays of arbitrary depth use a loop:

Object array = new int[10][][][];
Class<?> type = array.getClass();
while (type.isArray())
{
    type = type.getComponentType();
}
assert type == Integer.TYPE;

Generic Types (e.g. ArrayList<Integer>)

It is not possible to get the type parameter. Java uses type erasure, so the information is lost at runtime.

You can guess the declared type of collections based on the types of the elements:

import java.util.*;

public class CollectionTypeGuesser
{
    static Set<Class<?>> supers(Class<?> c)
    {
        if (c == null) return new HashSet<Class<?>>();

        Set<Class<?>> s = supers(c.getSuperclass());
        s.add(c);
        return s;
    }

    static Class<?> lowestCommonSuper(Class<?> a, Class<?> b)
    {
        Set<Class<?>> aSupers = supers(a);
        while (!aSupers.contains(b))
        {
            b = b.getSuperclass();
        }
        return b;
    }

    static Class<?> guessElementType(Collection<?> collection)
    {
        Class<?> guess = null;
        for (Object o : collection)
        {
            if (o != null)
            {
                if (guess == null)
                {
                    guess = o.getClass();
                }
                else if (guess != o.getClass())
                {
                    guess = lowestCommonSuper(guess, o.getClass());
                }
            }
        }
        return guess;
    }

    static class C1 { }
    static class C2 extends C1 { }
    static class C3A extends C2 { }
    static class C3B extends C2 { }

    public static void main(String[] args)
    {
        ArrayList<Integer> listOfInt = new ArrayList<Integer>();
        System.out.println(guessElementType(listOfInt)); // null
        listOfInt.add(42);
        System.out.println(guessElementType(listOfInt)); // Integer

        ArrayList<C1> listOfC1 = new ArrayList<C1>();
        listOfC1.add(new C3A());
        System.out.println(guessElementType(listOfC1)); // C3A
        listOfC1.add(new C3B());
        System.out.println(guessElementType(listOfC1)); // C2
        listOfC1.add(new C1());
        System.out.println(guessElementType(listOfC1)); // C1
    }
}
like image 116
tom Avatar answered Nov 10 '22 01:11

tom


You could use the classes getComponentType(). For example.

public static final Class<?> getBaseType(Object obj) {
    Class<?> type = obj.getClass();
    while (type.isArray()) {
        type = type.getComponentType();
    }
    return type;
}

type will then be whatever the base type is.

This will work if obj is double[][][][][][] or just double[], or something else.

As for generics, those things in < and >. Type erasure occurs, meaning you cannot determine what type those are from the ArrayList itself.

like image 26
Chase Avatar answered Nov 10 '22 02:11

Chase