Getting Type instance of implemented interface with type parameters applied

Given a Type instance (which may be a Class or ParameterizedType), I need to get the specific Type of an interface implemented by the class. Without generics this is easy, call getInterfaces() on a Class instance and you're done. However, I need this to work even when the implemented interface has its own type parameters that may or may not depend on the type parameters of the original class itself.

Some examples, the function should return Iterable<Integer> when given a class

class Foo implements Iterable<Integer> {}

but must also return Iterable<String> given the class

class Bar<T> implements Iterable<T> {}

and a ParmeterizedType representing Bar<String>

Is there an easy way to do this with built in reflection, third party tools etc?

To clarify, this needs to work not only with type instances retrieved via literals (Foo.class etc), but also those returned via reflection that can contain applied type parameters, for example the return type returned via reflection from the method

static Bar<String> magic() { ... }

This would be a ParameterizedType referencing the raw Bar class and the String type argument.


You should probably have a look at the Google Guava TypeToken class: http://code.google.com/p/guava-libraries/wiki/ReflectionExplained

It offers sophisticated mechanisms for resolving types in various contexts. And if I understood your question correctly, then something like the TypeToken#resolveType(Type) method might be close to what you are looking for:

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Iterator;

import com.google.common.reflect.TypeToken;

class Foo implements Iterable<Integer> {

    @Override
    public Iterator<Integer> iterator()
    {
        return null;
    }
}

class Bar<T> implements Iterable<T> {

    @Override
    public Iterator<T> iterator()
    {
        return null;
    }
}

public class TypeParameterTest
{
    public static void main(String[] args) throws Exception
    {
        Type i0 = getInterface(Foo.class, 0);
        System.out.println("First interface implemented by Foo: "+i0);

        Method method = TypeParameterTest.class.getDeclaredMethod("magic");
        Type returnType = method.getGenericReturnType();

        System.out.println("Magic method return type: "+returnType);

        Type i1 = getInterface(returnType, 0);
        System.out.println("First interface implemented by Bar<String>: "+i1);
    }

    private static Type getInterface(Type type, int interfaceIndex)
    {
        TypeToken<?> typeToken = TypeToken.of(type);
        Class<?> c = typeToken.getRawType();
        Type[] interfaces = c.getGenericInterfaces();
        if (interfaces.length == 0)
        {
            return null;
        }
        Type i = interfaces[interfaceIndex];
        return typeToken.resolveType(i).getType();
    }

    public static Bar<String> magic() { return null; }
}

The output here is

First interface implemented by Foo: java.lang.Iterable<java.lang.Integer>
Magic method return type: Bar<java.lang.String>
First interface implemented by Bar<String>: java.lang.Iterable<java.lang.String>

You can use reflections when the type is hard coded because it subclasses a specific type. Here the type is stored in the class information.

If you use reflections, you can see that Foo extends Iterable<String> but if you have a Bar<String> this is just a Bar at runtime due to type erasure and all you see is that Bar extends Iterable<T>

If you have a generic type which is parameterised, this is not recorded anywhere as it has no action at runtime. If you need this type, you need save it as an additional field.

eg There is a class Collections.CheckedMap which checks the types at runtime and it starts like this

private static class CheckedMap<K,V>
    implements Map<K,V>, Serializable
{
    private static final long serialVersionUID = 5742860141034234728L;

    private final Map<K, V> m;
    final Class<K> keyType;
    final Class<V> valueType;

这是一个使用ParameterizedType的例子

import java.lang.reflect.*;

public class Foo {

  static class Bar<T> {

  }
  static class SubBar extends Bar<Integer> {

  }

  public static void main(String argv[]) {

    ParameterizedType pt = (ParameterizedType)SubBar.class.getGenericSuperclass();
    Type[] t = pt.getActualTypeArguments();

    for (int i=0;i<t.length;i++) {

       System.out.println(t[i]);
    }
  }
}
链接地址: http://www.djcxy.com/p/57408.html

上一篇: 如何找出类成员是静态的还是Java中的字段

下一篇: 获取应用了类型参数的已实现接口的Type实例