Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何获得间接实现的泛型接口的实际类型参数?_Java_Generics_Reflection_Interface - Fatal编程技术网

Java 如何获得间接实现的泛型接口的实际类型参数?

Java 如何获得间接实现的泛型接口的实际类型参数?,java,generics,reflection,interface,Java,Generics,Reflection,Interface,我有一个参数化的接口,它以多种不同的方式实现。在运行时,我需要弄清楚,给定一个实现该接口的任意对象,接口的实际类型参数是什么 下面是一个片段来说明这个问题,以及解决这个问题的一个半途而废的尝试(): import java.util.*; 导入java.lang.reflect.*; 接口{} 类基类实现了{} 类子级扩展基{} 类{ 公共静态void main(字符串[]args){ 令人敬畏的x=新孩子(); System.out.println( ((参数化类型) Child.class.

我有一个参数化的接口,它以多种不同的方式实现。在运行时,我需要弄清楚,给定一个实现该接口的任意对象,接口的实际类型参数是什么

下面是一个片段来说明这个问题,以及解决这个问题的一个半途而废的尝试():

import java.util.*;
导入java.lang.reflect.*;
接口{}
类基类实现了{}
类子级扩展基{}
类{
公共静态void main(字符串[]args){
令人敬畏的x=新孩子();
System.out.println(
((参数化类型)
Child.class.getGenericSuperclass()
).getActualTypeArguments()[0]
);
//打印“java.util.List”
System.out.println(
((参数化类型)
Base.class.GetGenericInterface()[0]
).getActualTypeArguments()[0]
);
//打印“java.util.Set”
调查(x);
//我们要打印“Set”
}
静态空洞调查(可怕的某物可怕的某物){
//如何做到这一点?
}
}
运行时似乎有足够的泛型类型信息来推断:

  • 子扩展基
  • Base实现了Awesome
因此,我们可以把所有的细节放在一起得出结论:

  • Child实现了Awesome

看起来这个问题是可以解决的,但并没有那么简单,因为我们必须处理任意的类/接口层次结构。这是唯一的办法吗?有没有更简单的方法?有人写了一个图书馆来做这件事吗?

简短的回答是没有。我同意这是一个遗憾…:( 原因是Java在编译阶段删除类型参数。它们不存在于字节码中。它们仅由编译器使用

要解决您的问题,您必须添加另一个Class类型的“常规”参数,并在创建Base实例时将其传递给构造函数:

class Base<E> implements Awesome<Set<E>> { 
    private E type;
    public Base(E type) {
        this.type = type;
    }
}
类基类实现了{
私有E型;
公共基地(E型){
this.type=type;
}
}

编辑:您可能只想使用:

如果您可以保证
Awesome
的所有实现都不会有类型参数,那么应该从以下代码开始[1]:

static void investigate(Object o) {
    final Class<?> c = o.getClass();
    System.out.println("\n" + c.getName() + " implements: ");
    investigate(c, (Type[])null);
}

static void investigate(Type t, Type...typeArgs) {
    if(t == null) return;

    if(t instanceof Class<?>) {
        investigate((Class<?>)t, typeArgs);
    } else if(t instanceof ParameterizedType) {
        investigate((ParameterizedType)t, typeArgs);
    }
}

static void investigate(Class<?> c, Type...typeArgs) {
    investigate(c.getGenericSuperclass(), typeArgs);

    for(Type i : c.getGenericInterfaces()) {
        investigate(i, typeArgs);
    }
}

static void investigate(ParameterizedType p, Type...typeArgs) {
    final Class<?> c = (Class<?>)p.getRawType();
    final StringBuilder b = new StringBuilder(c.getName());
    b.append('<');
    Type[] localArgs = p.getActualTypeArguments();
    if(typeArgs != null && typeArgs.length > 0) {
        int i = 0, nextTypeArg = 0;
        for(Type local : localArgs) {
            if(local instanceof ParameterizedType) {
                ParameterizedType localP = (ParameterizedType) local;
                b.append(localP.getRawType()).append('<');
                b.append(typeArgs[nextTypeArg++]);
                b.append('>');
            } else if(local instanceof TypeVariable) {
                // reify local type arg to instantiated one.
                localArgs[nextTypeArg] = typeArgs[nextTypeArg];
                b.append(localArgs[nextTypeArg]);
                nextTypeArg++;
            } else {
                b.append(local.toString());
            }
            b.append(", ");
            i++;
        }
        if(typeArgs.length > 0) {
            b.delete(b.length() - 2, b.length());
        }
        b.append('>');
    } else {
        String args = Arrays.toString(localArgs);
        b.append(args.substring(1, args.length()-1)).append('>');
    }
    System.out.println(b);
    investigate(c, localArgs);
}
由于上述代码尚未完全测试,您可能需要这样做。这里的要点是,如果您的要求足够严格,您可以找到实际的类型参数。这是否适用于您的情况取决于您自己

[1] 它将打印出一个类实现的所有接口&不仅仅是
Awesome
的类型参数。这是可以更改的,但我想我会更一般一些,让您了解具体情况。例如,您需要测试这些接口以了解我的意思:

investigate(new ArrayList<Integer>());
investigate(new ArrayList<String>() {}); // new anonymous ArrayList class
investigate("");
investigate(new Awesome<Comparable<?>> () {}); // new anonymous implementation of Awesome
调查(新建ArrayList());
调查(新ArrayList(){});//新的匿名ArrayList类
调查(“”);

调查(新的Awesome以下是@oconnor0的建议,下面是如何使用:

静态类型调查(somesomengawesome){
返回GenericTypeReflector.getTypeParameter(somethingAwesome.getClass(),Awesome.class.getTypeParameters()[0]);
}
如果
somethingAwesome.getClass()
也可能是泛型的,那么首先通过
GenericTypeReflector.addWildcardParameters
传递它可能会很有用


Spring还有一个可以实现相同结果的方法。

类型信息在字节码中。因此您不正确。您可以在这个位置获取类型信息。谷歌搜索超级类型标记以获取示例。@Thomas-静态类型信息存储,动态信息不存储。我不知道有哪个库实现了这一点。我是自己做的elf-这不是很令人愉快。我至少可以找到一个超级类型令牌实现:
Awesome<?> awesome = new Base<Double>() {};
class Base<E> implements Awesome<Set<E>> {

    public static Base<Number> newNumberInstance() {
        return new Base<Number> () {};
    }

    protected Base() {}
}
investigate(new ArrayList<Integer>());
investigate(new ArrayList<String>() {}); // new anonymous ArrayList class
investigate("");
investigate(new Awesome<Comparable<?>> () {}); // new anonymous implementation of Awesome
static Type investigate(Awesome<?> somethingAwesome) {
    return GenericTypeReflector.getTypeParameter(somethingAwesome.getClass(), Awesome.class.getTypeParameters()[0]);
}