108

I got a list, programmed like this: public class MyList<T>. Is there any way to use the T variable to get the name of class (so I can, from within MyList, know if T is String, Socket, etc.)?

EDIT: Nevermind, found the answer here.

1

5 Answers 5

145

Short answer: You can't.

Long answer:

Due to the way generics is implemented in Java, the generic type T is not kept at runtime. Still, you can use a private data member:

public class Foo<T> 
{
    private Class<T> type;

    public Foo(Class<T> type) { this.type = type; } 
}

Usage example:

Foo<Integer> test = new Foo<Integer>(Integer.class);
Sign up to request clarification or add additional context in comments.

Comments

76

I like the solution from

http://www.nautsch.net/2008/10/28/class-von-type-parameter-java-generics/

public class Dada<T> {

    private Class<T> typeOfT;

    @SuppressWarnings("unchecked")
    public Dada() {
        this.typeOfT = (Class<T>)
                ((ParameterizedType)getClass()
                .getGenericSuperclass())
                .getActualTypeArguments()[0];
    }
...

6 Comments

This solution works fine for me. Advantage is no need to pass additional parameters like other solutions mentioned. Any issues when using this?
it's still working fine
This will only work if the runtime class is a direct subclass of the generic superclass.
This DOESN'T work with dynamic proxies so popular in modern frameworks.
Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
|
29

You are seeing the result of Type Erasure. From that page...

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.

For instance, Box<String> is translated to type Box, which is called the raw type — a raw type is a generic class or interface name without any type arguments. This means that you can't find out what type of Object a generic class is using at runtime.

This also looks like this question which has a pretty good answer as well.

Comments

4

I'm not 100% sure if this works in all cases (needs at least Java 1.5):

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

public class Main 
{
    public class A
    {   
    }

    public class B extends A
    {       
    }


    public Map<A, B> map = new HashMap<Main.A, Main.B>();

    public static void main(String[] args) 
    {

        try
        {
            Field field = Main.class.getField("map");           
            System.out.println("Field " + field.getName() + " is of type " + field.getType().getSimpleName());

            Type genericType = field.getGenericType();

            if(genericType instanceof ParameterizedType)
            {
                ParameterizedType type = (ParameterizedType) genericType;               
                Type[] typeArguments = type.getActualTypeArguments();

                for(Type typeArgument : typeArguments) 
                {   
                    Class<?> classType = ((Class<?>)typeArgument);                  
                    System.out.println("Field " + field.getName() + " has a parameterized type of " + classType.getSimpleName());
                }
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }    
}

This will output:

Field map is of type Map
Field map has a parameterized type of A
Field map has a parameterized type of B

3 Comments

Once I tried to do similar during refactoring of General DAO, so I went through some similar code samples. Don't remember why, but I decided not to go with such approach (I think it didn't work well in all cases, maybe class hierarchy was mandatory). Your example does work :) +1 P.S. Some extended tutorial I've found: artima.com/weblogs/viewpost.jsp?thread=208860
I found the original article where I lifted this from (the example above is extracted from one of our work-projects): tutorials.jenkov.com/java-reflection/generics.html#fieldtypes The article says this only works with public-fields, but that's not true, you can access protected and private fields via reflection too (just use getDeclaredField instead of getField)
This does not answer the question. This gets the type used in declaring a field. How is this relevant?
3

I'm able to get the Class of the generic type this way:

class MyList<T> {
  Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(MyList.class, this.getClass()).get(0);
}

You need two functions from this file: http://code.google.com/p/hibernate-generic-dao/source/browse/trunk/dao/src/main/java/com/googlecode/genericdao/dao/DAOUtil.java

For more explanation: http://www.artima.com/weblogs/viewpost.jsp?thread=208860

3 Comments

Here, MyList.class and this.getClass() both are same value!!
Yes, you can. This works: public String getParameterTypeName() { return ((Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]) .getTypeName(); }

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.