Kotlin如何从泛型类参数获取T::class.java?Corda仓库构建报错
解决Corda Vault通用仓库中获取泛型T类型信息的问题
嘿,这个问题我在构建Corda通用Vault仓库时也踩过坑!核心原因是Java/Kotlin的泛型类型擦除——编译后泛型参数T的实际类型信息会被抹掉,所以直接在VaultRepository<T>里拿T的Class对象是行不通的。不过有两种可靠的办法能解决这个问题:
方案1:构造函数显式传入Class(推荐)
这是最直接且灵活的方案,主动把类型信息传递给仓库,完全避开类型擦除的限制。
用Kotlin实现的示例:
class VaultRepository<T : ContractState>( private val stateClass: Class<T>, private val serviceHub: ServiceHub ) { fun queryVault(): List<T> { return serviceHub.vaultService.queryBy(stateClass) .states.map { it.state.data } } } // 实例化的时候直接传类型 val myStateRepo = VaultRepository(MyState::class.java, serviceHub) val states = myStateRepo.queryVault()
嫌每次传::class.java麻烦?可以封装一个inline reified的辅助函数简化调用:
inline fun <reified T : ContractState> createVaultRepo(serviceHub: ServiceHub): VaultRepository<T> { return VaultRepository(T::class.java, serviceHub) } // 这样调用更清爽 val myStateRepo = createVaultRepo<MyState>(serviceHub)
这里reified只能用在inline函数里,编译时会把T替换成实际类型,完美解决类型传递问题。
方案2:通过子类继承保留类型信息
如果你的业务场景里每个ContractState都需要专属的仓库实现,这个方案会更简洁——让子类继承通用仓库,利用反射获取父类的泛型参数:
示例代码:
abstract class BaseVaultRepository<T : ContractState>( protected val serviceHub: ServiceHub ) { // 懒加载获取T的Class对象 private val stateClass: Class<T> by lazy { val genericSuperclass = javaClass.genericSuperclass as ParameterizedType genericSuperclass.actualTypeArguments[0] as Class<T> } fun queryVault(): List<T> { return serviceHub.vaultService.queryBy(stateClass) .states.map { it.state.data } } } // 为每个状态创建专属仓库子类 class MyStateRepository(serviceHub: ServiceHub) : BaseVaultRepository<MyState>(serviceHub) // 使用时直接实例化子类 val myStateRepo = MyStateRepository(serviceHub) val states = myStateRepo.queryVault()
这个方案的缺点是要为每个状态写子类,但好处是使用时不用再传类型信息。
为什么会碰到Cannot use 'T' as reified type parameter?
简单说:Kotlin的reified关键字只能用在inline函数里,类的泛型参数不支持reified。因为reified是靠编译时内联替换实现的,而类的泛型参数在运行时还是会被擦除,没办法保留类型信息,所以编译器会报错。
总结一下,优先选方案1,灵活性更高;如果是固定状态的专属仓库,方案2更顺手。
内容的提问来源于stack exchange,提问作者Matthew Layton
相关产品推荐
相关产品推荐

