【问题标题】:Java: generic classes explanation of codeJava:泛型类代码解释
【发布时间】:2016-03-14 15:48:23
【问题描述】:

来自 C++,一些 Java 代码对我来说看起来很奇怪。有人可以向我解释以下代码片段应该做什么吗?

@SuppressWarnings("unchecked")
private static <T> Class<T> getGenericType(Class<?> clz) {
    return (Class<T>) ((ParameterizedType) clz.getGenericSuperclass())
            .getActualTypeArguments()[0];
}

我在回答另一个问题 (see here) 时阅读了这篇文章,我正试图详细了解该问题。

【问题讨论】:

  • 它返回泛型的类型,所以如果你通过ArrayList&lt;String&gt; - 它会返回String
  • 老实说,我认为它只是为了@SuppressWarnings。除了调用getActualTypeArguments(),这段代码实际上没有做任何事情。泛型基本上都从实际的运行时代码中删除了。
  • “另一个问题”还有哪个问题?
  • @Lashane 你不能把这个方法传递给 ArrayList;它的参数类型是Class 不过你可以传入ArrayList&lt;String&gt;.class
  • @markspace 没有ArrayList&lt;String&gt;.class,只有ArrayList.class

标签: java generics syntax


【解决方案1】:

假设你有一个泛型类Foo,像这样:

public class Foo<T> {
    T myVar;
}

在很多方面,这就像 C++ 中的模板。 T 是某种类型,可能是String,可能是Integer,可能是Object,可能是SomeTypeYouveNeverHeardOf,这一切都取决于使用Foo 的代码,而不是Foo 中的代码。

还有它的一个子类,Bar:

public class Bar extends Foo<String> {}

Bar 不是泛型类,尽管它使用一个作为其超类。它指定,对于Bar 的所有实例,类型变量T 实际上是String,因此它从Foo 继承的myVar 实例变量将始终是String

现在已经解决了这个设置,让我们转向你的方法。

首先,它将Class 对象作为其参数。假设我们用Bar.class 调用它。你的方法做的第一件事是在它上面调用getGenericSuperclass(),它检索一个代表它的超类的对象——Foo&lt;String&gt;

现在,getGenericSuperclass() 被声明为返回一个Type 对象,但代码假设传入的类具有通用继承(即,它扩展类似Foo&lt;String&gt; 而不仅仅是Foo) ,在这种情况下,它实际上会返回一个ParameterizedType。所以它类型转换它并调用getActualTypeArguments() 来检索类型参数是什么——extends Foo&lt;String&gt;String 部分。这是作为数组返回的,因为在更一般的情况下,它可能会处理像 extends ComplexObject&lt;String, Integer, Foo, Object&gt; 这样的事情。

在获得一个大小为 1 的 Class 对象数组后,它会返回该数组的第一个成员。在本例中,返回值为String.class

【讨论】:

    【解决方案2】:

    这个方法在我的系统上做了什么,现在我测试了它,就是在运行时抛出一个异常。所以我猜它的作用是“没什么用”。

    public class GenericTest
    {
    
       public static void main( String[] args )
       {
          ArrayList<String> al = new ArrayList<>();
          System.out.println( getGenericType( al.getClass() ) );
       }
    
       @SuppressWarnings( "unchecked" )
       private static <T> Class<T> getGenericType( Class<?> clz )
       {
          return (Class<T>) ( (ParameterizedType) clz.getGenericSuperclass() )
                  .getActualTypeArguments()[0];  // line 28
       }
    }
    
    run:
    Exception in thread "main" java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
        at quicktest.GenericTest.getGenericType(GenericTest.java:28)
        at quicktest.GenericTest.main(GenericTest.java:21)
    C:\Users\Brenden\AppData\Local\NetBeans\Cache\8.1\executor-snippets\run.xml:53: Java returned: 1
    BUILD FAILED (total time: 2 seconds)
    

    【讨论】:

    • 那是因为你正在传递它ArrayList.class(以稍微迂回的方式检索),它在继承中不使用泛型。
    • 我应该传入什么类类型?
    • extends 子句包含通用尖括号的任何内容。 ArrayList 的匿名子类,如 @Lashane` 指出的,应该可以工作(注意 {})。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多