You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin反射:如何检查类属性是否为特定类型的ArrayList

Kotlin反射检查属性是否为特定泛型ArrayList类型

刚接触Kotlin和Java,想通过反射检查属性类型是否为ArrayList<Pair<String, ByteArray>>,现有代码如下:

class DataUploadFormData {
    var files: ArrayList<Pair<String, ByteArray>> = arrayListOf()
    var collection: String? = null
}

// DataUploadFormData type is passed here as T
suspend inline fun <reified T : Any> mapFormData(data: MultiPartData): T? {
    val formData: FormData = getFormData(data)
    val model: T? = getValue()
    var fields = T::class.memberProperties
    fields.forEach { field ->
        if (field is KMutableProperty<*>) {
            setFieldValue(field, formData, model)
        }
    }

    return model
}


@OptIn(ExperimentalStdlibApi::class)
fun <T> setFieldValue(field: KMutableProperty<*>, formData: FormData, model: T?) {
    var value: Any? = null

    if (field.returnType.javaType == String::class.createType().javaType ||
        field.returnType.javaType == Int::class.createType().javaType ||
        field.returnType.javaType == Double::class.createType().javaType
    ) {
        value = formData.fields.firstOrNull(predicate = { it.first == field.name })?.second
    }
    else if (
    // check if field.returnType is of ArrayList<Pair<String, ByteArray>> type?
    ) {
        value = formData.files
    }

    field.setter.call(model, value)
}

目前简单数据类型的检查已经正常工作,但不清楚如何检查复杂泛型类型。尝试过实例化属性用is判断,但无法通过field.returnType.javaType::class.createInstance()实例化;用field.returnType.classifier is ArrayList<*>判断返回false。


解决方案

要准确判断泛型类型,需要利用Kotlin反射中KType的泛型参数信息——类型擦除会导致直接通过javaType无法获取泛型细节。可以按照以下步骤判断:

  1. 先判断属性返回类型的分类器(classifier)是否为ArrayList::class
  2. 再获取ArrayList的泛型参数,检查是否为Pair<String, ByteArray>:
    • 判断该泛型参数的分类器为Pair::class
    • 检查Pair的两个类型参数分别为String::class和ByteArray::class

修改后的setFieldValue函数代码如下:

@OptIn(ExperimentalStdlibApi::class)
fun <T> setFieldValue(field: KMutableProperty<*>, formData: FormData, model: T?) {
    var value: Any? = null

    if (field.returnType.javaType == String::class.createType().javaType ||
        field.returnType.javaType == Int::class.createType().javaType ||
        field.returnType.javaType == Double::class.createType().javaType
    ) {
        value = formData.fields.firstOrNull(predicate = { it.first == field.name })?.second
    }
    else if (
        // 第一步:判断是ArrayList类型
        field.returnType.classifier == ArrayList::class &&
        field.returnType.arguments.size == 1
    ) {
        val listElementType = field.returnType.arguments[0].type ?: return
        // 第二步:判断ArrayList的元素是Pair类型,且参数匹配
        if (listElementType.classifier == Pair::class &&
            listElementType.arguments.size == 2) {
            val firstArg = listElementType.arguments[0].type ?: return
            val secondArg = listElementType.arguments[1].type ?: return
            if (firstArg.classifier == String::class && secondArg.classifier == ByteArray::class) {
                value = formData.files
            }
        }
    }

    field.setter.call(model, value)
}

关键说明

  • 用field.returnType.classifier == ArrayList::class替代is ArrayList<*>:classifier返回的是KClass<*>实例,直接用==判断是否为目标类的KClass更准确,is用于判断实例类型,此处不适用。
  • 必须通过KType.arguments获取泛型参数:类型擦除后,javaType无法保留泛型信息,而Kotlin的KType会在编译期保留这些信息(前提是反射的类型是reified或者有完整的类型签名)。

内容的提问来源于stack exchange,提问作者Andrew Krachko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 18:47:33