Kotlin中如何引用Any类型类的变量以避免未解析引用
解决方案
情况1:可修改目标类源码
定义一个包含所需字段的接口,让所有相关类实现该接口,从根源上解决编译类型问题:
// 定义统一接口,包含所有需要访问的字段 interface BarData { val unixSecond: Long val open: Double val high: Double val low: Double val close: Double val volume: Double } // 让所有需要处理的类实现这个接口(示例) class Algobar( override val unixSecond: Long, override val open: Double, override val high: Double, override val low: Double, override val close: Double, override val volume: Double, // 其他自定义字段 ) : BarData class ThirdPartyBar( override val unixSecond: Long, override val open: Double, override val high: Double, override val low: Double, override val close: Double, override val volume: Double, // 第三方类原有字段 ) : BarData
修改函数参数类型为List<BarData?>,编译时即可正常访问字段,同时替换原代码中语义不符的map为forEach(仅执行副作用无需返回新列表):
fun createTA4JBarsFromAlgobars(timebars: List<BarData?>, name: String): BaseBarSeries? { val series = BaseBarSeriesBuilder().withName(name).build() timebars.forEach { bar -> bar?.let { series.addBar( utilService.unixtimeToZoneDateTime(it.unixSecond), it.open, it.high, it.low, it.close, it.volume ) } } return series }
情况2:无法修改目标类源码(如第三方类)
方法A:类型判断+智能转换
如果已知所有可能的类类型,通过when分支做类型判断,Kotlin会自动进行智能转换,保证编译安全:
fun createTA4JBarsFromAlgobars(timebars: List<Any?>, name: String): BaseBarSeries? { val series = BaseBarSeriesBuilder().withName(name).build() timebars.forEach { item -> when (item) { is Algobar -> addBarToSeries(series, item) is ThirdPartyBar -> addBarToSeries(series, item) // 后续新增类型只需添加对应分支 } } return series } // 提取公共逻辑,避免代码重复 private fun addBarToSeries(series: BaseBarSeries, bar: Any) { when (bar) { is Algobar -> series.addBar( utilService.unixtimeToZoneDateTime(bar.unixSecond), bar.open, bar.high, bar.low, bar.close, bar.volume ) is ThirdPartyBar -> series.addBar( utilService.unixtimeToZoneDateTime(bar.unixSecond), bar.open, bar.high, bar.low, bar.close, bar.volume ) } }
方法B:反射统一处理
如果类数量多或类型不确定,可通过Kotlin反射动态获取字段值(注意:反射有性能开销,需确保字段名称和类型完全匹配):
import kotlin.reflect.full.memberProperties fun createTA4JBarsFromAlgobars(timebars: List<Any?>, name: String): BaseBarSeries? { val series = BaseBarSeriesBuilder().withName(name).build() timebars.forEach { item -> item?.let { obj -> // 反射获取字段值并做类型转换 val unixSecond = obj::class.memberProperties.find { it.name == "unixSecond" }?.get(obj) as? Long val open = obj::class.memberProperties.find { it.name == "open" }?.get(obj) as? Double val high = obj::class.memberProperties.find { it.name == "high" }?.get(obj) as? Double val low = obj::class.memberProperties.find { it.name == "low" }?.get(obj) as? Double val close = obj::class.memberProperties.find { it.name == "close" }?.get(obj) as? Double val volume = obj::class.memberProperties.find { it.name == "volume" }?.get(obj) as? Double // 所有字段非空时才添加 if (unixSecond != null && open != null && high != null && low != null && close != null && volume != null) { series.addBar( utilService.unixtimeToZoneDateTime(unixSecond), open, high, low, close, volume ) } } } return series }
内容的提问来源于stack exchange,提问作者Joachim Karlsson
相关产品推荐
相关产品推荐

