如何将已有父类实例的值传递给子类实例(非反射方案)
解决方案:父类实例转子类实例并传递属性
为什么强制转换行不通
你写的代码里,dog是Dog类的实例,它本质上不是Dalmatian的实例,Kotlin的类型转换as只是向编译器声明“我确认这个实例是目标类型”,但运行时会检查实际类型,不匹配就会抛出ClassCastException。所以这种强制转换的思路从根本上不可行。
优先方案:非反射实现属性传递
1. 子类添加接收父类的构造函数
直接在子类里定义构造函数接收父类实例,手动复制父类属性值,再初始化子类自身属性:
open class Dog { var height = -1 } class Dalmatian: Dog() { var dots = -1 // 新增接收Dog实例的构造函数 constructor(dog: Dog): this() { // 复制父类属性 this.height = dog.height } } fun main() { val dog = Dog().apply { height = 24 } // 用新构造函数创建子类实例,自动继承父类属性 val dalmatian = Dalmatian(dog).apply { dots = 101 } println(dalmatian.height) // 输出24 println(dalmatian.dots) // 输出101 }
2. 父类实现复制逻辑,子类扩展
如果父类属性较多或存在多个子类,可以在父类中编写copyTo方法,子类重写后补充自身属性的复制逻辑:
open class Dog { var height = -1 // 父类提供属性复制方法 open fun copyTo(dog: Dog) { dog.height = this.height } } class Dalmatian: Dog() { var dots = -1 // 子类重写,补充自身属性复制 fun copyTo(dalmatian: Dalmatian) { super.copyTo(dalmatian) dalmatian.dots = this.dots } // 编写从Dog实例创建自身的方法 fun fromDog(dog: Dog): Dalmatian { val dal = Dalmatian() dog.copyTo(dal) return dal } } fun main() { val dog = Dog().apply { height = 24 } val dalmatian = Dalmatian().fromDog(dog).apply { dots = 101 } println(dalmatian.height) // 输出24 println(dalmatian.dots) // 输出101 }
3. 利用数据类的copy特性(父类可改为数据类时)
如果父类可以改为数据类,它自带的copy方法能简化属性传递:
data class Dog(var height: Int = -1) class Dalmatian(dog: Dog, var dots: Int = -1): Dog(dog.height) fun main() { val dog = Dog(24) val dalmatian = Dalmatian(dog, 101) println(dalmatian.height) // 输出24 println(dalmatian.dots) // 输出101 }
备选方案:反射实现(适合属性较多的场景)
如果父类属性数量多,手动复制过于繁琐,可以用Kotlin反射自动复制所有父类属性到子类实例:
import kotlin.reflect.full.memberProperties open class Dog { var height = -1 } class Dalmatian: Dog() { var dots = -1 } fun <T: Dog> Dog.toSubclass(subclass: Class<T>): T { val instance = subclass.getDeclaredConstructor().newInstance() // 复制父类所有可变属性 this::class.memberProperties.forEach { prop -> if (prop is kotlin.reflect.KMutableProperty<*>) { prop.set(instance, prop.get(this)) } } return instance } fun main() { val dog = Dog().apply { height = 24 } val dalmatian = dog.toSubclass(Dalmatian::class.java).apply { dots = 101 } println(dalmatian.height) // 输出24 println(dalmatian.dots) // 输出101 }
注意:反射会带来性能开销,且需要处理访问权限问题,非必要不推荐使用。
内容的提问来源于stack exchange,提问作者Developer-Mike
相关产品推荐
相关产品推荐

