如何在Kotlin中对自定义对象的数组进行序列化/反序列化?

6
在我的Kotlin Android项目中,我创建了一个FileItem类,它扩展了Serializable。
class FileItem(<parameters>) : Serializable, Comparable<FileItem> {

所以我需要将这个类的实例序列化为一个 Bundle

val arguments:Bundle = Bundle()
arguments.putSerializable("folders", folders as Serializable)

其中folders已声明为:

folders:Array<FileItem> (method parameter)

上述的序列化代码编译时没有任何警告。然而,当我需要反序列化文件夹项目时,问题就出现了:
val arguments: Bundle? = getArguments()
if (arguments != null){
    foldersItems = arguments.getSerializable("folders") as Array<FileItem>

其中foldersItems被声明为

var foldersItems: Array<FileItem>?

我收到以下警告,如果没有使用suppress_warning注释,我无法解决:
w: <Path to my class>: (78, 28): Unchecked cast: java.io.Serializable! to kotlin.Array<com.loloof64.android.chess_positions_archiver.main_file_explorer.FileItem>

这种代码在Java/Groovy中编译时没有警告(folderItems是FileItem[]),那么我该如何修改kotlin代码以使编译器“满意”?
我注意到在官方Kotlin文档中,Kotlin数组不扩展Serializable,也不开放继承。是否可以通过某种扩展方法“添加”它?

1
关于数组序列化,它们在 Kotlin 中也是可序列化的。这段代码展示了它:https://gist.github.com/h0tk3y/bc892327ab239121e76df645d32d9832。我不知道为什么参考资料没有说明,可能是因为 Array<SomeType> 编译成了 Java 的 SomeType[],后者肯定是可序列化的。 - hotkey
2个回答

5
实际上,类型转换并没有未经检查,编译器的警告是误导性的。
这是因为在 Kotlin 中,数组由泛型类 Array<T> 表示,编译器将其视为通常的泛型类,在运行时擦除类型参数。
但在 JVM 上,数组具有实体类型,当您将 something 转换为 Array<SomeType> 时,生成的字节码确实检查类型参数是否为 SomeType,以及 something 是否为 Array<*>,这只会发生在任何其他泛型类中。
这个例子展示了数组转换是被检查的:
val a: Any = Array<Int>(1) { 0 }

val i = a as Array<Int>
val d = a as Array<Double> // gets checked and throws ClassCastException

最简单的解决方案确实是 @Suppress("UNCHECKED_CAST"),因为实际上不应该有任何警告。

我在 Kotlin 问题跟踪器中提交了一个 问题描述


好的。抱歉重复了,当我创建讨论时你的链接还没有被提供。 - loloof64
也许这是一个简单的问题,但在我的示例中(我尝试将Serializable检索到folders数组中),您会把注释放在哪里:我无法消除警告。我尝试过foldersItems = @Suppress("UNCHECKED_CAST") arguments.getSerializable("folders") as Array<FileItem>。 - loloof64
1
@loloof64 这应该可以工作:foldersItems = @Suppress("UNCHECKED_CAST") (arguments.getSerializable("folders") as Array<FileItem>)。或者只需注释封闭函数即可。 - hotkey

1
这里的类型转换未经检查,因为编译器无法确保数组泛型类型参数的可空性。
考虑以下示例:
fun castAsArrayOfString(param: Any) = param as Array<String>

castAsArrayOfString(arrayOf("a")) // is Array<String>, all ok

castAsArrayOfString(arrayOf("a", null)) // is Array<String>, but contains null

所以编译器警告您这种转换可能会引入潜在的类型安全问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接