如何解决Kotlin调用Java泛型方法时ID类型变量无法推断问题
Kotlin调用Java泛型方法的类型参数推断问题解决
你在将Java代码转换为Kotlin时,遇到了Java泛型方法TableUtils.dropTable的调用编译错误。该Java方法签名如下:
public static <T, ID> int dropTable(ConnectionSource connectionSource, Class<T> dataClass, boolean ignoreErrors) throws SQLException
在Java中,即使类型变量ID未知也能正常编译:
public void method(ConnectionSource connectionSource, Class<? extends IRecordObject> clazz) { try { TableUtils.dropTable(connectionSource, clazz, true); // 编译正常 } catch (SQLException e) { e.printStackTrace(); } }
但转换为Kotlin后,代码因无法推断ID类型变量而编译失败:
fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) { try { TableUtils.dropTable(connectionSource, clazz, true) // 编译错误:"Not enough information to infer type variable ID" } catch (e: SQLException) { e.printStackTrace(); } }
尝试显式指定类型参数时,Kotlin不允许在泛型函数调用中使用out投影,导致以下代码同样报错:
TableUtils.dropTable<out IRecordObject,Long>(connectionSource, clazz, true) // 编译错误:"Projections are not allowed on type arguments of functions and properties"
解决方法
方法1:显式指定类型参数并强转Class类型
由于Kotlin不允许在泛型调用时使用out投影,我们可以将clazz强转为Class<IRecordObject>(配合注解抑制未检查转换的警告),同时显式指定ID为任意兼容类型(比如Any?,如果不需要具体ID类型的话):
@Suppress("UNCHECKED_CAST") fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) { try { TableUtils.dropTable<IRecordObject, Any?>(connectionSource, clazz as Class<IRecordObject>, true) } catch (e: SQLException) { e.printStackTrace() } }
方法2:使用星号投影处理未知的ID类型
如果ID类型在方法内部没有实际被使用(从Java方法签名看,参数列表中未涉及ID相关的输入),可以用Kotlin的星号投影*来表示该类型参数的任意可能值,同样配合强转:
@Suppress("UNCHECKED_CAST") fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) { try { TableUtils.dropTable<IRecordObject, *>(connectionSource, clazz as Class<IRecordObject>, true) } catch (e: SQLException) { e.printStackTrace() } }
方法3:利用Java的类型推断兼容性(可选)
如果不想在Kotlin中处理类型转换,可以编写一个简单的Java工具方法封装dropTable的调用,然后在Kotlin中调用这个Java方法,借助Java宽松的类型推断绕过问题:
// Java工具类 public class KotlinTableUtils { public static <T extends IRecordObject> int dropTable(ConnectionSource connectionSource, Class<T> clazz, boolean ignoreErrors) throws SQLException { return TableUtils.dropTable(connectionSource, clazz, ignoreErrors); } }
然后在Kotlin中调用:
fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) { try { KotlinTableUtils.dropTable(connectionSource, clazz, true) } catch (e: SQLException) { e.printStackTrace() } }
内容的提问来源于stack exchange,提问作者Adam Burley
相关产品推荐
相关产品推荐

