【问题标题】:Java - Getting the name of generic classJava - 获取泛型类的名称
【发布时间】:2020-07-06 14:01:43
【问题描述】:

我有以下两个类:

class Generic<T> 
{

}

class Foo extends Generic<Student>
{

}

Generic 内部,我有一个方法需要获取通过T 传递的类的名称

这在 Java 中可能吗?我知道在 C# 中我只会使用 typeof

我已尝试执行以下操作:

String className = new TypeToken<T>() {}.getClass().getName().toString();

然而,这不提供名称,只提供Generic$1

【问题讨论】:

  • 您无法有效地创建泛型类型标记。您可以通过查看其泛型超类型的类型参数从非泛型类型标记(例如new TypeToken&lt;String&gt;() {}new TypeToken&lt;List&lt;Integer&gt;&gt;() {})中获取该类;但该类型参数是该类型标记的类型变量 T。
  • 我重新打开了,因为它不是声称的问题的副本。在这种情况下,可以通过Foo 访问该类型(尽管此处要求子类不使用参数)。

标签: java spring


【解决方案1】:

使用 getGenericSuperclass() 方法并检查是否是 ParameterizedType 然后使用返回 Type 数组的 getActualTypeArguments() 获取所有参数, 请记住,泛型类可能使用多个类型,例如 Map (Map)

public Class<?> getGenericType(Object obj) {
    Class<?> genericType = null;
    Type gnrcType = obj.getClass().getGenericSuperclass();
    if (gnrcType instanceof ParameterizedType) {
        ParameterizedType parameterizedType = (ParameterizedType) gnrcType;
        Type types[] = parameterizedType.getActualTypeArguments();

        if (types != null && types.length > 0) {
            Type type = types[0];
            if (type instanceof Class) {
                genericType = (Class<?>) type;
            }
        }
    }
    return genericType;
}

【讨论】:

    【解决方案2】:

    我假设Generic&lt;T&gt; 始终是一个为类型参数提供实际类的类的子类,如Foo 代码中所示。在这种情况下,仍然可以使用Class.getGenericSupertype 获得类型信息。这是一个简单的例子。

    import java.lang.reflect.*;
    
    class Generic<T> 
    {
        public String name() {
            Class<?> clazz = this.getClass();
            for (;;) {
                Class<?> superClass = clazz.getSuperclass();
                if (superClass == null) {
                    throw new IllegalStateException();
                }
                if (superClass == Generic.class) {
                    Type genericSuper = clazz.getGenericSuperclass();
                    if (genericSuper instanceof ParameterizedType) {
                        ParameterizedType parameterized = (ParameterizedType)genericSuper;
                        Type[] params = parameterized.getActualTypeArguments();
                        if (params.length == 1) {
                            Type param = params[0];
                            if (param instanceof Class<?>) {
                                return ((Class<?>)param).getName();
                            }
                        }
                    }
                    throw new IllegalStateException();
                }
                clazz = superClass;
            }
        }
    }
    
    class Foo extends Generic<Student>
    {
    
    }
    interface Student {}
    
    interface Code {
       static void main(String[] args) {
           System.err.println(new Foo().name());
       }
    }
    

    那只处理简单的情况。例如,如果 Foo extends Generic&lt;Set&lt;Student&gt;&gt;T 不是 Class

    【讨论】:

      【解决方案3】:

      获取泛型类名称的简单方法。

      定义一个泛型类

      public class GenericClass<T> {
      
      private final Class<T> type;
      
      public GenericClass(Class<T> type) {
           this.type = type;
      }
      
      public Class<T> getType() {
          return this.type;
      }
      

      }

      使用这个泛型类作为参数

      GenericClass type = new GenericClass(MyEntity.class);
      exampleMethod(type);
      

      在exampleMethod方法中

      public void exampleMethod(GenericClass type) {
          String fullName= type.getType().getCanonicalName(); //"com.example.MyEntity"
          String sortName= type.getType().getSimpleName(); //"MyEntity"
      }
      

      【讨论】:

      • 很好,但是如果这个类必须在同类型的泛型父类中初始化,而不是在构造函数中呢?
      【解决方案4】:

      C# 和 Java 以非常不同的方式实现泛型。

      C# 在运行时具有真正的泛型和泛型信息。出于向后兼容性的原因,Java 使用类型擦除 - 这就是编译器中的所有通用魔法,它在任何地方都用 Object 代替 T,在运行时你不知道泛型类型。

      Java 泛型仍然优于 C++ 模板,后者并不比编译时的宏替换好。但是 Java 不能在不破坏与旧版本运行时/字节码的向后兼容性的情况下进行 C# 风格的泛型。

      总而言之,你不能在 Java 中做到这一点。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-28
        • 1970-01-01
        相关资源
        最近更新 更多