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

Java 获取应用了类型参数的已实现接口的类型实例,java,generics,reflection,Java,Generics,Reflection,给定一个类型实例(可能是类或ParameterizedType),我需要获取该类实现的接口的特定类型。如果没有泛型,这很容易,在类实例上调用getInterfaces(),就完成了。但是,即使实现的接口有自己的类型参数,这些参数可能取决于原始类本身的类型参数,也可能不取决于原始类本身的类型参数,我仍然需要这样做 在一些示例中,当给定一个类时,函数应该返回Iterable class Foo implements Iterable<Integer> {} 类Foo实现了Iterabl

给定一个类型实例(可能是类或ParameterizedType),我需要获取该类实现的接口的特定类型。如果没有泛型,这很容易,在类实例上调用getInterfaces(),就完成了。但是,即使实现的接口有自己的类型参数,这些参数可能取决于原始类本身的类型参数,也可能不取决于原始类本身的类型参数,我仍然需要这样做

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

class Foo implements Iterable<Integer> {}
类Foo实现了Iterable{}
但也必须返回给定类的Iterable

class Bar<T> implements Iterable<T> {}
类栏实现了Iterable{}
和表示条的参数化数据类型

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

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

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

这将是一个参数化类型,引用原始条形图类和字符串类型参数。

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

如果您使用反射,您可以看到
Foo
extends
Iterable
,但是如果您有
Bar
,由于类型擦除,在运行时这只是一个
Bar
,您所看到的就是
Bar
extends
Iterable

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

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;
私有静态类CheckedMap
实现映射,可序列化
{
私有静态最终长serialVersionUID=5742860141034234728L;
私人最终地图m;
最终类键类型;
最终类值类型;

以下是使用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]);
    }
  }
}
import java.lang.reflect.*;
公开课Foo{
静态分类栏{
}
静态类子条扩展条{
}
公共静态void main(字符串argv[]){
ParameteredType pt=(ParameteredType)SubBar.class.getGenericSuperclass();
类型[]t=pt.getActualTypeArguments();
对于(int i=0;i
import java.lang.reflect.ParameterizedType;
导入java.lang.reflect.Type;
导入java.util.Iterator;
公共类Dummy实现了Iterable{
公共静态void main(字符串args[])引发异常{
假人d=新假人();
类型[]genericInterfaces=Dummy.class.getGenericInterfaces();
for(类型genericInterface:genericInterface){
if(参数化类型的通用接口实例){
类型[]genericTypes=((ParameterizedType)genericInterface).getActualTypeArguments();
for(类型genericType:genericTypes){
System.out.println(“泛型:“+genericType”);
}
}
}
}
@凌驾
公共迭代器迭代器(){
//TODO自动生成的方法存根
返回null;
}
}

您可能应该看看Google Guava
TypeToken
类:

它提供了在各种上下文中解析类型的复杂机制。如果我正确理解了您的问题,那么类似
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; }
}
import java.lang.reflect.Method;
导入java.lang.reflect.Type;
导入java.util.Iterator;
导入com.google.common.reflect.TypeToken;
类Foo实现了Iterable{
@凌驾
公共迭代器迭代器()
{
返回null;
}
}
类栏实现了Iterable{
@凌驾
公共迭代器迭代器()
{
返回null;
}
}
公共类类型参数测试
{
公共静态void main(字符串[]args)引发异常
{
类型i0=getInterface(Foo.class,0);
System.out.println(“Foo实现的第一个接口:“+i0”);
Method=TypeParameterTest.class.getDeclaredMethod(“magic”);
类型returnType=method.getGenericReturnType();
System.out.println(“神奇方法返回类型:“+returnType”);
类型i1=getInterface(returnType,0);
System.out.println(“由Bar实现的第一个接口:“+i1”);
}
私有静态类型getInterface(类型类型,int interfaceIndex)
{
TypeToken TypeToken=TypeToken.of(类型);
c类=typeToken.getRawType();
类型[]interfaces=c.getGenericInterfaces();
if(interfaces.length==0)
{
返回null;
}
i类=接口[接口索引];
返回typeToken.resolveType(i).getType();
}
公共静态条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>
Foo实现的第一个接口:java.lang.Iterable Magic方法返回类型:Bar Bar实现的第一个接口:java.lang.Iterable
这根本不是真的。我使用反射来读取方法的返回类型,该返回类型将以ParameterizedType的形式包含完整的类型,包括应用的类型参数。@SoftMemes您只能读取烧录到类信息中的类型,而不能读取在运行时创建的类型。Peter写道,不推荐这样做修复使其成为可能,但反射不是这样。除了传递泛型参数和方法参数有什么区别之外?这有两个问题。首先,它是基类而不是接口,对于我的情况,我需要一个接口。其次,当SubBar也有类型pa时,它不会给我正确的答案传递的参数(可能在内部)
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>