获取祖先类的泛型类型的类

3
有没有一种简单的方法可以获取祖先类的泛型参数?(不是直接父类,如此处所讨论的:http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/,而是在继承层次结构中的任何祖先类。)
例如:假设我们有以下类:
class Class1<O,P,Q> {}

class Class2<R,S> extends Class1<R, String, S> {}

class Class3<U> extends Class2<List,U> {}

class Class4<W> extends Class2<W,Set> {}

给定一个特定的子类(例如Class3Class4),我如何知道祖先类Class1参数的类型?请注意,所有这些信息都在编译时存在!例如,我知道对于Class3<U>Class1将实例化为:<List,String,U>。同样,对于Class4<W>Class1将实例化为<W,String,Set>。因此,应该可以通过反射来完成此操作。请注意,我不关心参数的运行时值,而只关心编译时数据。感谢您的帮助!

好问题...我不知道你能从反射中获取参数化类型...我认为叫做"类型擦除"的东西会妨碍这个过程...在编译期间,所有对实际类型的引用都被删除了。如果有答案,我会很感兴趣。干杯。Keith. - corlettk
嗨@corlettk,据我所知,类型擦除会删除有关类型的运行时类型信息,而不是编译时信息。请注意,即使这个说法并不完全正确,因为在我上面发布的链接中讨论过的,你仍然可以通过一些技巧获取运行时信息。 - Sergio
我刚刚阅读了链接的“教程”。有趣。我猜你可以拿那段代码并扩展它,以查找O、P和Q的参数化类型在继承层次结构中...假设可以在调用.getGenericSuperclass()的结果上调用.getGenericSuperclass()...我会去尝试一下(可能需要一段时间),然后发布某种答案。干杯。 - corlettk
正如您在最后一段所展示的那样,您可以通过沿着层次结构向上追踪来轻松找到自己。既然这不是在运行时进行的,为什么需要在代码中这样做呢? - Chad Schouggins
@ChadSchouggins,我的意思是我需要的信息在编译时可用。但是特定子类的名称仅在运行时才知道。 - Sergio
嗨@corlettk,我认为它可以被编程,但我认为很烦人的是Java中没有API可以轻松地询问这种问题。我认为Java的反射协议和类型系统非常混乱、不完整且补丁式的。 - Sergio
2个回答

1

Ian Robertson提出了一个公平的解决方案。据我回忆,它并不完整,但它应该可以让你轻松入手。


是的,这是从原帖的代码无法继续运行的地方开始的... 我应该在发表评论之前阅读完整篇文章。唉。 - corlettk

1

好的,这里有一种方法...我并不是说这是最好的(甚至不是一个好的)方法,我只是说你可能能够根据自己的需求进行调整。

package forums;
import java.util.List;
import java.util.Set;
import java.lang.reflect.*;

class Class1<O,P,Q> {}

class Class2<R,S> extends Class1<R, String, S> {}

class Class3<U> extends Class2<List,U> {}

class Class4<W> extends Class2<W,Set> {}

public class GenericTypeHeirarchy
{
  public static void main(String[] args) {
    try {
      PrintGenericAncestorTypes(Class4.class, "    ");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  @SuppressWarnings("unchecked")
  public static void PrintGenericAncestorTypes(Class clazz, String pad) {
    Type supaType = clazz.getGenericSuperclass();
    ParameterizedType paramSupaType = null;
    if (supaType instanceof ParameterizedType)
      paramSupaType = (ParameterizedType) supaType;
    if (paramSupaType == null)
      return; // INVALID REQUEST! Parent isn't a generic type.
    Type[] supasArgTypes = paramSupaType.getActualTypeArguments();  //actually returns TypeVariableImpl[]
    for ( Type t : supasArgTypes ) {
      // Type subinterfaces: GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType
      if (t instanceof TypeVariable) {
        System.out.println( pad + clazz.getName() + ": <" + t + ">");
        PrintGenericAncestorTypes(clazz.getSuperclass(), pad + "    "); // <<<< RECURSION >>>>
      } else {
        System.out.println( pad + clazz.getName() + ": " + t);
      }
    }
  }

}

编辑:

这可能仍然不是您想要的...我认为您需要的是每个泛型参数类型的类(或类名)...但这已经是我能到达的极限了。我不知道如何为Type获取Class... Type接口为空,因此必须将其转换为某些内容才能从中获取类(或类名),而read-arg-types(例如java.lang.String)并不是Type的任何已知子接口(GenericArrayType、ParameterizedType、TypeVariable或WildcardType)。我假设是的一个实例。

所以这是我的改进版本,但我被卡住了,不知道该怎么办。

package forums;
import java.util.List;
import java.util.Set;
import java.lang.reflect.*;

class Class1<O,P,Q> {}

class Class2<R,S> extends Class1<R, String, S> {}

class Class3<U> extends Class2<List,U> {}

class Class4<W> extends Class2<W,Set> {}

public class GenericTypeHeirarchy
{
  public static void main(String[] args) {
    try {
      PrintGenericTypeTree(Class4.class);
      System.out.println("--------------------------\n");
      PrintGenericTypeTree(Class3.class);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  //@SuppressWarnings("unchecked")
  public static void PrintGenericTypeTree(Class clazz) {
    if (clazz == null || clazz == java.lang.Object.class)
      return;
    //
    // class Class4<W> extends
    //
    System.out.print( "class " + clazz.getName() );
    TypeVariable[] argTypes = clazz.getTypeParameters();
    if (argTypes.length == 0)
      return;
    System.out.print( "<" );
    boolean first = true;
    for ( TypeVariable t : argTypes ) {
      System.out.print( (first?"":", ") + t.getName() );
      first = false;
    }
    System.out.print("> extends ");
    //
    // Class2<W,Set>
    //
    Class supaClass = clazz.getSuperclass();
    System.out.print(supaClass.getName());
    Type genericSupaType = clazz.getGenericSuperclass();
    ParameterizedType paramSupaType = null;
    if (genericSupaType instanceof ParameterizedType)
      paramSupaType = (ParameterizedType) genericSupaType;
    if (paramSupaType == null) { // Parent isn't a generic type.
      System.out.println();
      return; 
    }
    Type[] supasArgTypes = paramSupaType.getActualTypeArguments();  //actually returns TypeVariableImpl[]
    first = true;
    System.out.print( "<" );
    for ( Type t : supasArgTypes ) {
      System.out.print( (first?"":", ") + t );
      first = false;
    }
    System.out.println(">");
    PrintGenericTypeTree(supaClass);
  }

}

... 这里是输出结果 ...

C:\Java\home\src\forums>"C:\Program Files\Java\jdk1.6.0_16\bin\java.exe" -Xms4m -Xmx256m -enableassertions -cp c:\java\home\src;C:\Java\home\classes; forums.GenericTypeHeirarchy

class forums.Class4<W> extends forums.Class2<W, interface java.util.Set>
class forums.Class2<R, S> extends forums.Class1<R, class java.lang.String, S>
class forums.Class1<O, P, Q> extends java.lang.Object
--------------------------

class forums.Class3<U> extends forums.Class2<interface java.util.List, U>
class forums.Class2<R, S> extends forums.Class1<R, class java.lang.String, S>
class forums.Class1<O, P, Q> extends java.lang.Object

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接