【问题标题】:Getting Type instance of implemented interface with type parameters applied获取应用类型参数的已实现接口的类型实例
【发布时间】:2014-02-25 12:23:29
【问题描述】:

给定一个 Type 实例(可能是 Class 或 ParameterizedType),我需要获取该类实现的接口的特定 Type。如果没有泛型,这很容易,在 Class 实例上调用 getInterfaces() 即可。但是,即使实现的接口有自己的类型参数,这些参数可能依赖于或不依赖于原始类本身的类型参数,我也需要它来工作。

一些例子,当给定一个类时,函数应该返回 Iterable

class Foo implements Iterable<Integer> {}

但也必须在给定类的情况下返回 Iterable

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

和一个代表 Bar

的 ParmeterizedType

有没有一种简单的方法可以通过内置反射、第三方工具等来做到这一点?

澄清一下,这不仅需要使用通过文字检索的类型实例(Foo.class 等),还需要使用那些通过反射返回的可以包含应用类型参数的实例,例如通过方法反射返回的返回类型

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

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

【问题讨论】:

    标签: java generics reflection


    【解决方案1】:

    您可能应该看看 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>
    

    【讨论】:

    • 我相信这正是我所需要的,是的!如果可以的话,我会放弃 10 票:)
    【解决方案2】:

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

    如果你使用反射,你可以看到 Foo 扩展 Iterable&lt;String&gt; 但如果你有一个 Bar&lt;String&gt; 这只是一个 Bar 在运行时由于类型擦除,你看到的只是 Bar 扩展Iterable&lt;T&gt;

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

    例如有一个类 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;
    

    【讨论】:

    • 这根本不是真的。我正在使用反射来读取包含完整类型的方法的返回类型,包括应用的类型参数,以 ParameterizedType 的形式。
    • @SoftMemes 只能读取刻录到类信息中的类型,不能读取运行时创建的类型。
    • 彼得写道,不建议这样做,所以它可能,但反射并非如此。除了传递泛型参数和方法参数有什么区别?
    【解决方案3】:

    这里是一个使用 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]);
        }
      }
    }
    

    【讨论】:

    • 这有两个问题。首先,它是基类而不是接口,就我而言,我需要一个接口。其次,当 SubBar 也传递了类型参数(可能在其他类型中)时,它不会给我正确的答案。
    • Type[] genericInterfaces = BarFoo.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); } }
    • 在传递类型参数的情况下仍然没有实际应用类型参数。这最终会得到一个未解析的 TypeVariable。
    【解决方案4】:
    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;
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 2010-11-11
    • 2014-07-31
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    • 2010-09-06
    • 1970-01-01
    相关资源
    最近更新 更多