Kotlin泛型问题:实现接口的泛型类实例化报错如何解决?
报错原因
- 属性无限递归问题:
AppUserModel中所有属性的getter、setter都直接调用了属性自身,没有用到Kotlin的幕后字段field,访问任何属性都会触发无限递归,最终抛出StackOverflowError。同时这种写法没有存储属性值的载体,属性完全无法正常工作。 - 泛型声明冲突:
EADBAccess的泛型参数T添加了in关键字(声明处逆变),逆变泛型只能作为方法参数的输入类型,但是你在代码中将T作为ResultHandlerI.onSuccess的返回值类型(输出位置),违反了逆变约束,直接导致编译报错。 - 语法错误:
EADBAccess的类声明关键字写错,Kotlin中定义类需要用小写的class,你写的大写Class是Java中表示类类型的对象,属于语法错误,编译无法通过。
解决方案
1. 修正AppUserModel的属性定义
直接简化声明使用Kotlin默认生成的getter/setter,如需自定义逻辑请用field指代幕后字段:
class AppUserModel : EADBModelI { // 直接赋值默认值,Kotlin自动生成带幕后字段的getter/setter override var id: String = "" var name: String = "" }
如果需要自定义get/set逻辑,示例写法如下:
override var id: String = "" get() = field.trim() // 用field访问幕后字段,不要用id set(value) { field = value.trim() // 赋值给field,不要直接给id赋值 }
2. 修正EADBAccess的泛型与语法
去掉泛型前的in关键字,修正类声明的关键字为小写class:
// 去掉in修饰符,class小写,泛型为不变类型同时支持输入输出 class EADBAccess<T : EADBModelI>(private val typeParameterClass: Class<T>) { fun getSingleDocument(source: Source = Source.DEFAULT, docRef: DocumentReference, handler: ResultHandlerI<T>) { docRef.get(source).addOnCompleteListener { taskResult -> if (taskResult.isSuccessful) { val snapshot = taskResult.result if (snapshot!!.exists()) { val model : T = snapshot.toObject(typeParameterClass) model!!.id = snapshot.reference.id handler.onSuccess(model) } } else { handler.onFailure(taskResult.exception) } } } }
3. 可选优化:用Kotlin具体化泛型简化实例化
可以通过内联函数+具体化泛型省略手动传入Class对象的步骤:
// 定义顶层内联函数 inline fun <reified T : EADBModelI> EADBAccess(): EADBAccess<T> = EADBAccess(T::class.java)
实例化代码可简化为:
val access = EADBAccess<AppUserModel>()
内容的提问来源于stack exchange,提问作者Azeem Muzammil
相关产品推荐
相关产品推荐

