例如,我有一个People
类型的列表。我的列表只能包含Student
类型的元素或Worker
类型的元素:
interface People {
val name: String
val age: Int
}
data class Student(
override val name: String,
override val age: Int,
val course: Int
) : People
data class Worker(
override val name: String,
override val age: Int,
val position: String
) : People
在某些时候,我需要知道列表的确切类型(student或worker)。我能安全地找到确切类型吗?到目前为止,我已经写了下面的代码,但看起来不是很好:
fun someLogic(items: List<People>): List<People> {
return (items as? List<Student>) ?: (items as? List<Worker>)
?.filter {}
....
}
同时,我收到警告:
未检查的转换
你能告诉我如何正确地执行这样的转换吗?
3条答案
按热度按时间w46czmvw1#
在运行时,用于创建列表的类型参数不可用。例如,无法区分以下两种情况:
这是因为类型擦除。
在运行时,可以帮助确定列表元素类型的唯一信息是其元素的类型。
因此,如果一个列表没有元素,就没有办法知道它是什么类型的列表,尽管在大多数情况下,你根本不需要知道。
因此,假设列表只能是所有学生的列表或所有工人的列表,而不能是包含学生和工人的混合列表,则可以通过检查第一个元素来确定列表的类型。
另一方面,如果你想得到
List<Student>
或List<Worker>
out,你可以使用filterIsInstance
:无论哪个列表不为空,则
items
的类型是该列表的类型。5f0d552i2#
如果您想检查
List<People>
是否为List<Student>
,可以使用以下扩展函数:如果您想将
List<People>
转换为List<Student>
,您可以使用map,这个类型转换是安全的,所以假设有一些People
不是Student
,所以这个类型转换会返回null而不是Student
,因为as?
和mapNotNull
会排除null元素,所以在最坏的情况下,当你传递一个不包含t包含任何Student
这个函数将返回一个空列表:或者您可以只使用
filterIsInstance<Student>
,其工作方式与上面的toStudentList
相同:同样的方法也可以用于
Worker
axzmvihb3#
我会用更具体的类来解决这个问题。
您可以定义:
然后你可以很容易地检查这些列表的类型,每个类都可以保证你没有在同一个
List
中混合Student
和Worker
对象,这是你不能用普通的List<People>
对象做的。还要注意,如果可能的话,你最好在编写代码时避免检查类型。最好在
PeopleList
接口中添加方法,并强制子类实现它们,例如:然后,您可以在适当的时候调用这些方法,而不是检查类型。这种方法将与这些子类型关联的功能与这些子类型保持在一起,而不是分散在代码中您必须检查
PeopleList
类型的各个点。