How to construct a parameterized class literal from two existing class literals?

时间:2017-08-04 12:47:32

标签: java class generics literals

I'd wonder, if and how it is possible to achieve the below, while only beeing able to use the two class literal variables:

Class<Foo<Bar>> getFoobar(){

    Class<Foo> fooClass = Foo.class;
    Class<Bar> barClass = Bar.class;

    // ... combine and return Class<Foo<Bar>>
}

... with the restriction, that it is not possible to use the types literally, but ok to retrieve the types programmatically from the class literal variables.

1 个答案:

答案 0 :(得分:1)

我们不能使用类型参数(正如你已经注意到的那样),即我们不能指望像T.classnew T()这样的表达式可以工作,因为我们对泛型类型做不了多少“编程”。参数化类型在编译后会丢失其类型参数,因此对于Foo<T>类型的以下实例:

Foo<String> foostr...;
Foo<Bar> foobar...;

我们将拥有相同的Class对象,即

foostr.getClass() == foobar.getClass() == Foo.class

因此,允许Foo<String>.classFoo<Bar>.class等类文字是没有意义的。

这就是编译类型下泛型类型的许多限制背后的原因:由于在运行时没有关于类型参数的信息(因为类型擦除),我们必须在编译时限制很多可能性

在运行时使用泛型类型的一种可能性是将有关类Foo及其类型参数Bar的信息提取为ParameterizedType对象,例如

class Bar {
  ...
}

class Foo<T> {
  ...
}

class Foobar extends Foo<Bar> {

  ParameterizedType getFoobar() {
    return (ParameterizedType)getClass().getGenericSuperclass();
  }
}

...

Foobar foobar = new Foobar();
System.out.println(foobar.getFoobar().getRawType()); // Foo.class
System.out.println(foobar.getFoobar().getActualTypeArguments()[0]); // Bar.class

另一种方法基于第一种方法,但更容易实现,是使用FasterXML Jacson Project中的TypeReference(或创建自己的类)来捕获参数化类型:

class Foo<T> { ... }

class Bar { ... }

TypeReference typeReference = new TypeReference<Foo<Bar>>() {};  
ParameterizedTypeImpl parametrizedType = (ParameterizedTypeImpl) typeReference.getType();
System.out.println(parametrizedType.getTypeName()); // Foo<Bar>
System.out.println(parametrizedType.getRawType()); // Foo
System.out.println(parametrizedType.getActualTypeArguments()[0]); // Bar

请详细了解ParameterizedTypeImpl#toString()方法的实现。