You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 14:06:24