获取已应用类型参数的已实现接口的Type实例

时间:2014-02-25 12:23:30

标签: java generics reflection

给定一个Type实例(可能是Class或ParameterizedType),我需要获取该类实现的特定类型的接口。如果没有泛型,这很简单,在Class实例上调用getInterfaces()就可以了。但是,即使实现的接口有自己的类型参数,也可能依赖于原始类本身的类型参数,我仍然需要这个。

一些例子,该函数应该返回Iterable< Integer>什么时候上课

class Foo implements Iterable<Integer> {}

但也必须返回Iterable&lt; String&gt;鉴于班级

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

和表示Bar&lt; String&gt;

的ParmeterizedType

使用内置反射,第三方工具等可以轻松实现此目的吗?

为了澄清,这不仅需要通过文字(Foo.class等)检索的类型实例,还需要通过可以包含应用类型参数的反射返回的类型实例,例如通过方法反射返回的返回类型< / p>

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

这将是引用原始Bar类和String类型参数的ParameterizedType。

4 个答案:

答案 0 :(得分:2)

您应该查看Google Guava TypeToken课程:http://code.google.com/p/guava-libraries/wiki/ReflectionExplained

它提供了用于在各种上下文中解析类型的复杂机制。并且如果我正确理解了您的问题,那么TypeToken#resolveType(Type)方法之类的内容可能与您正在寻找的内容接近:

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

这里的输出是

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>

答案 1 :(得分:0)

当类型为硬编码时,您可以使用反射,因为它是特定类型的子类。这里的类型存储在类信息中。

如果您使用反射,则可以看到Foo扩展Iterable<String>,但如果您有Bar<String>,则由于类型擦除而在运行时这只是Bar你看,Bar扩展Iterable<T>

如果您具有参数化的泛型类型,则不会在任何地方记录,因为它在运行时没有操作。如果您需要此类型,则需要将其另存为附加字段。

e.g。有一个类Collections.CheckedMap在运行时检查类型,它就像这样开始

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;

答案 2 :(得分:0)

以下是使用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]);
    }
  }
}

答案 3 :(得分:0)

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

public class Dummy implements Iterable<Integer> {

    public static void main(String args[]) throws Exception {

        Dummy d = new Dummy();

        Type[] genericInterfaces = Dummy.class.getGenericInterfaces();

        for (Type genericInterface : genericInterfaces) {
            if (genericInterface instanceof ParameterizedType) {
                Type[] genericTypes = ((ParameterizedType) genericInterface).getActualTypeArguments();

                for (Type genericType : genericTypes) {

                    System.out.println("Generic type: " + genericType);
                }
            }
    }
    }

    @Override
    public Iterator<Integer> iterator() {
        // TODO Auto-generated method stub
        return null;
    }

}