Kotlin 1.7+调用Java递归泛型方法遇类型越界错误的解决方法
问题描述
Java端定义
我使用一个Java定义的泛型接口:
public interface MyClass<T extends MyClass<T, D>, D> { .. }
Java类FindClassFromString中包含一个泛型方法:
public <D, T extends MyClass<T, D>> Class<T> findClassFromString(String type) { ... }
在Java中调用该方法时,会触发未检查转换警告,但属于可接受范围:
var findClassFromString = new FindClassFromString(); Class<MyClass<?, ?>> clazz = (Class<MyClass<?, ?>>) findClassFromString.findClassFromString("SomeString");
Kotlin调用兼容性问题
在Kotlin 1.6.21版本中,我可以通过以下方式调用(会收到UPPER_BOUND_VIOLATED_WARNING警告,可接受):
val clazz = findClassFromString.findClassFromString<Any, MyClass<*, *>>("SomeString") // 类型为Class<MyClass<*, *>>
但升级到Kotlin 1.7及以上版本后,出现编译错误:
Type argument is not within its bounds. Expected: MyClass<MyClass<*, *>!, TypeVariable(D)!>! Found: MyClass<*, *>! Type argument is not within its bounds. Expected: Nothing! Found: Any!
请问如何让这段Kotlin代码在1.7+版本中编译通过?
解决方案
方案1:显式unchecked转换+抑制警告
和Java的调用逻辑对齐,通过显式强制转换绕过Kotlin 1.7+更严格的泛型边界检查,同时用注解抑制相关警告:
@Suppress("UNCHECKED_CAST", "UPPER_BOUND_VIOLATED") val clazz = findClassFromString.findClassFromString("SomeString") as Class<MyClass<*, *>>
这种方式本质和Java的未检查转换警告一致,属于业务可接受的范围。
方案2:定义符合边界的占位符类型
通过定义一个严格满足MyClass泛型边界的占位符类型,让编译器通过检查,最后再转换到目标类型:
private typealias MyClassPlaceholder = MyClass<MyClassPlaceholder, Any> @Suppress("UPPER_BOUND_VIOLATED") val clazz = findClassFromString.findClassFromString<Any, MyClassPlaceholder>("SomeString") as Class<MyClass<*, *>>
MyClassPlaceholder完全符合T extends MyClass<T, D>的约束,能通过Kotlin 1.7+的编译校验。
方案3:利用协变放宽类型约束
由于Class本身支持协变,可使用Kotlin的out关键字适配类型,避免强制转换:
@Suppress("UPPER_BOUND_VIOLATED") val clazz: Class<out MyClass<*, *>> = findClassFromString.findClassFromString<Any, MyClass<*, *>>("SomeString")
此方式得到的是协变类型Class<out MyClass<*, *>>,如果业务逻辑兼容该类型,这是更安全的写法。
内容的提问来源于stack exchange,提问作者Johan
相关产品推荐
相关产品推荐

