我正在编写一个Kotlin程序,该程序在内部使用Java库的一些功能(我无法修改)。 该函数之一(被称为“ feval”)在被调用时将返回具有以下结构的对象:是大小为1的Object的数组,其唯一成员是com.mathworks.matlab.types的实例。结构。该结构的每个字段还是一个大小为1的数组,其唯一成员是一个变量,类型可以是int,double,Array等...这就是我感兴趣的值。
我想用一个类包装这种混乱,该类提供直接访问“有趣”值的方法。这是我的照片:
class ExecutionResult (fevalOutput: Array<Any>) {
private val rootObj = fevalOutput[0]
val rootStruct: Struct
init {
if (rootObj is Struct) {
rootStruct = rootObj
}
else {
throw ExecutionResultException("The output doesn't match the expected format")
}
}
fun _get (field: String) : Any {
val container = rootStruct.get(field)
?: throw NoSuchFieldException("The requested field cannot be found in the result")
if (container is Array<*>) {
val value = container[0]
if (value != null) {
return value
}
else {
throw NoSuchFieldException("The requested field cannot be found in the result")
}
}
else{
throw ExecutionResultException("The requested field has an unexpected format")
}
}
inline fun <reified T> get (field: String) : T {
val value = _get(field)
if (value is T) {
return value
}
else {
throw ExecutionResultException(
"The requested field is not a member of the specified class: ${T::class.java}," +
" but a member of: ${value::class.java}")
}
}}
现在,从我的代码中,我可以执行以下操作:
val output = engine.feval<Array<Any>>(1,functionName, *transmissionParameters.getParameters())
val result = ExecutionResult(output)
val simpleValue = result.get<Double>("simpleValue"))
基本上是我想要的。 但是,这并不总是有效。例如,有时我要查找的嵌套值是double数组的数组。如果我这样做:
val moreComplexValue = result.get<Array<Array<Double>>>("moreComplexValue"))
我生成以下异常:
Exception in thread "main" matlabdriver.ExecutionResultException: The requested field is not a member of the specified class: class [[Ljava.lang.Double;, but a member of: class [[D
如果我理解正确,则该问题是由于我试图将Java本机double数组转换为Double(类)数组而造成的
有人对如何解决这个问题和/或总体上改善我的包装器类有建议吗?
答案 0 :(得分:2)
问题在于类型擦除不能保留泛型的嵌套类型。就您而言,Array<Any>
将产生Array::class.java
,Array<Array<Double>>
也将产生结果。即使使用类型化的类型,该函数内部也只有顶级类可用。
Jackson(JSON序列化)库在反序列化为List<MyClass>
之类的通用类型时会遇到相同的问题。它们使您可以显式指定类型参数:
// represents the generic type Outer<Inner>
val type: JavaType = mapper.typeFactory.constructParametricType(Outer::class.java, Inner::class.java)
我建议您提供一种类似的机制来提供层次结构中的所有类型。也许告诉自己有关Jackson的JavaType
的信息,以了解其机制。使用Kotlin,您仍然可以使用带有修饰类型的通用语法,例如:
val type = dim3<Array, Array, Double>()
// or easier:
val type = array2<Double>()
然后您可以将该类型(将通用类型参数存储为类对象)传递为函数的第一个参数:
feval(type, otherArgs...)
type
本身可以是具有许多工厂功能的data class MatlabType(val subtypes: List<KClass>)
,例如array2()
。