Kotlin中如何实现对象类型转换?List<A>转List<B>及实体类与数据类的转换方案
Hey there! Let's break down your problem and figure out the best solutions, no unchecked warnings required.
First, let's fix the immediate issue: directly casting a List<AutoComplete> to List<PuntiVendita> with as gives an unchecked warning (and is unsafe!) because of generic type erasure. The JVM can't verify the type of every element in the list at runtime, so the compiler can't guarantee the cast is safe.
Instead, you should explicitly convert each element in the list. Since your AutoComplete and PuntiVendita classes have identical property structures, this is straightforward with Kotlin's map function:
// Safely retrieve the response body (avoid !! where possible, handle empty cases) val autoCompleteList = response.body() ?: emptyList() // Convert each AutoComplete to a PuntiVendita individually val puntiVenditaList: List<PuntiVendita> = autoCompleteList.map { autoComplete -> PuntiVendita(autoComplete.cod, autoComplete.desc) }
This eliminates the warning completely, is type-safe, and avoids runtime ClassCastException risks.
Now let's cover common patterns for converting generic lists in Kotlin, depending on your use case:
1. Manual Mapping with map (Most Common)
When the two classes have clear property mappings, using map to create new instances of B from each A is the simplest, safest approach.
If you need to reuse this conversion often, wrap it in an extension function for cleaner code:
// Add an extension function to List<AutoComplete> fun List<AutoComplete>.toPuntiVenditaList(): List<PuntiVendita> { return this.map { PuntiVendita(it.cod, it.desc) } } // Usage is concise: val puntiVenditaList = autoCompleteList.toPuntiVenditaList()
2. Use Mapping Libraries (For Complex Classes)
If you're dealing with classes with many properties or frequent conversions, a mapping library like MapStruct (Kotlin-compatible) can save you from writing repetitive code. It generates type-safe mapping logic at compile time.
Example setup:
import org.mapstruct.Mapper import org.mapstruct.factory.Mappers @Mapper interface AutoCompleteMapper { fun convertToPuntiVendita(autoComplete: AutoComplete): PuntiVendita fun convertToPuntiVenditaList(list: List<AutoComplete>): List<PuntiVendita> } // Get the mapper instance and use it val mapper = Mappers.getMapper(AutoCompleteMapper::class.java) val puntiVenditaList = mapper.convertToPuntiVenditaList(autoCompleteList)
MapStruct automatically handles matching property names, and you can customize mappings with annotations if needed.
3. Filter & Cast for Inheritance Hierarchies
If A and B are part of the same inheritance tree (e.g., B extends A), use filterIsInstance to safely extract and cast elements:
open class BaseEntity(val cod: String, val desc: String) class PuntiVendita(cod: String, desc: String) : BaseEntity(cod, desc) class AutoComplete(cod: String, desc: String) : BaseEntity(cod, desc) // Extract only PuntiVendita instances from a List<BaseEntity> val baseList: List<BaseEntity> = fetchData() val puntiVenditaList: List<PuntiVendita> = baseList.filterIsInstance()
filterIsInstance removes non-matching elements and returns a fully type-safe List<B> with no warnings.
To recap: Kotlin uses erased generics, so the JVM can't tell List<AutoComplete> apart from List<PuntiVendita> at runtime. The unchecked warning is the compiler's way of saying "I can't verify this is safe." If the list ever contains an element that isn't a PuntiVendita, your code will crash with a ClassCastException at runtime.
内容的提问来源于stack exchange,提问作者NiceToMytyuk

