首页 > 解决方案 > Kotlin 检查列表中具有擦除类型的元素是否是 Java 类的实例

问题描述

我有一个存储 a 的类,resultClass我想做一些类型检查并确保用户在调用getTypeSafeResults函数时获得类型安全列表。

class MyClass<T>(
    private val resultClass: Class<T>
){
    fun getTypeSafeResults() : List<T> {
        val results: List<Any?> = remoteFetchResults()
        return results.filterIsInstance(resultClass)
    }
}

这个 API 必须是 Java 友好的,因此 resultClass 是一个 Java 类。

但是,当resultClass=Integer::class.java/resultClass=Long::class.java和结果包含这些的 Kotlin 版本时,例如 kotlin.Int / kotlin.Long,它们与filterIsInstance(resultClass).

有没有办法手动检查 resultClass 是否是 Kotlin 类型的 Java 版本?我已经尝试过下面这段代码,但没有运气:

(什么时候it是 kotlin Long,it.javaClass.kotlin="class kotlin.Long"但是resultClass="long"

fun getTypeSafeResults(results: List<Any?>) : List<T> {
    return results.map {
        uncheckedCast(
            if (resultClass.isAssignableFrom(it.javaClass)) { // doesn't match kotlin long to java Long
                it 
            } else if (it.javaClass.kotlin == resultClass) { // doesn't match kotlin long to java Long
                it
            } else {
                throw Exception("Attempted to cast result of type ${it.javaClass} to $resultClass")
            }
        )
    }
}

标签: javakotlingenerics

解决方案


我做了一些实验来更好地理解发生了什么。

所有这些都正确找到了 42:

val list = listOf(42, 32L, "bob")
println(list.filter { it::class == Int::class })
println(list.filter { it::class == java.lang.Integer::class.java.kotlin })
println(list.filter { it::class == Int::class.java.kotlin })
println(list.filter { it.javaClass == Int::class.javaObjectType })
println(list.filter { it.javaClass == java.lang.Integer::class.java })

只有这不会:

println(list.filter { it.javaClass == Int::class.java })

因此,您可以做的是确保您使用的javaObjectType是用户为您提供的课程:

class MyClass<T : Any>(
    resultClass: Class<T>
){
    private val effectiveClass = resultClass.kotlin.javaObjectType

    fun getTypeSafeResults() : List<T> {
        val results: List<Any?> = remoteFetchResults()
        return results.filterIsInstance(effectiveClass)
    }
}

推荐阅读