Getting Class of list with generic eg: List

2019-02-12 08:32发布

问题:

I have a generically typed class Builder<T> that takes a constructor argument Class<T> so I can keep the type around. This is a class that I use a lot in java code so I don't want to change the signature. When I try to use the constructor like this:

Builder<List<Number>>(List<Number>::class)

I get an error: "Only classes are allowed on the left hand side of a class literal"

Any way to resolve this? I can't change the constructor for Builder, too many java classes rely upon it.

I understand the whole type erasure issue, I really just want to make the compiler happy.

回答1:

Due to generic type erasure List class has a single implementation for all its generic instantiations. You can only get a class corresponding to List<*> type, and thus create only Builder<List<*>>.

That builder instance is suitable for building a list of something. And again due to type erasure what that something is you can decide by yourself with the help of unchecked casts:

Builder(List::class.java) as Builder<List<Number>>
Builder(List::class.java as Class<List<Number>>)

Another approach is to create inline reified helper function:

inline fun <reified T : Any> Builder() = Builder(T::class.java)

and use it the following way:

Builder<List<Number>>()


回答2:

The solution is to use reified generics in couple with super class tokens.

Please refer to this question for the method explained. Constructors in Kotlin don't support reified generics, but you can use TypeReference described there to write a builder factory function which will retain actual generic parameters at runtime:

inline <reified T: Any> fun builder(): Builder<T> {
    val type = object : TypeReference<T>() {}.type
    return Builder(type)
}

Then inside Builder you can check if type is ParameterizedType, and if it is, type.actualTypeArguments will contain the actual generic parameters.

For example, builder<List<Number>>() will retain the information about Number at runtime.

The limitation of this approach is that you cannot use non-reified generic as a reified type parameter because the type must be known at compile-time.



回答3:

You might want to just use the following style,

Array<Number>::class.java

If you want something like Class<T>