【问题标题】:Obtaining classes of generic types of an ancestor class获取祖先类的泛型类
【发布时间】:2011-11-26 21:14:44
【问题描述】:

有没有一种简单的方法来获取祖先类的泛型参数? (不是直接父类,如此处所述: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&lt;U&gt;Class1 将被实例化为:&lt;List, String, U&gt;

同样,对于Class4&lt;W&gt;Class1 将被实例化为&lt;W, String, Set&gt;。所以应该可以通过反射来做到这一点。请注意,我对参数的运行时值不感兴趣,而对编译时数据感兴趣。

感谢您的帮助!!

【问题讨论】:

  • 好问题...我根本不知道您可以从重新选择中获得参数化类型...我认为称为“类型擦除”的东西妨碍了...所有参考到编译期间删除的实际类型。如果有的话,我会对这个问题的答案感兴趣。干杯。基思。
  • 嗨@corlettk,据我​​所知,类型擦除会删除运行时类型信息,而不是有关类型的编译时间信息。请注意,即使此声明也不是 100% 正确,因为您可以采取某些技巧来获取我在上面发布的链接中讨论的运行时间信息。
  • 我刚刚通读了链接的“教程”。有趣的。我想您可以使用该代码并扩展以在继承层次结构中查找 O、P 和 Q 的参数化类型...假设可以在调用 .getGenericSuperclass() 的结果上调用 .getGenericSuperclass()...我会去玩(可能需要一段时间)然后发布一些答案。干杯。
  • 正如您在上一段中演示的那样,您只需按照层次结构的线索即可轻松找到自己。为什么需要在代码中执行此操作(因为它不在运行时)?
  • @ChadSchouggins,我想说的是,我需要的信息在编译时可用。但是特定后代类的名称只有在运行时才知道。

标签: java generics reflection


【解决方案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);
      }
    }
  }

}

编辑:

这可能仍然不是您所追求的......我认为这将是每个泛型参数类型的类(或类名)......但这是我能得到的。我不知道如何获得一个类型的类......类型接口是空的,所以它必须被强制转换为从......和读取参数中获取一个类(或类名)的东西-types(如 java.lang.String),其中没有任何 known-subinterfaces-of-Type(GenericArrayType、ParameterizedType、TypeVariable 或 WildcardType)。我假设TypeVariable&lt;D&gt;instanceOf TypeVariable

所以这是我的改进版本,但我不知道从哪里开始。

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

【讨论】:

    【解决方案2】:

    Ian Robertson 想出了一个公平的solution。我记得它不完整,但它应该很容易让你开始。

    【讨论】:

    • 是的,从 OP 的代码给出的地方开始......我应该在评论之前阅读 COMPLETE 文章。叹息。
    猜你喜欢
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-22
    • 2015-11-20
    • 1970-01-01
    相关资源
    最近更新 更多