当前位置: 首页 > 知识库问答 >
问题:

Kotlin编译器无法验证类的泛型类型

胡弘毅
2023-03-14
fun <T: A()> getUtil(t: T): Util<T> = if (t is B) UtilB() else // ...

Kotlin编译器在这里发出警告(未检查的强制转换):

fun <T: A()> getUtil(t: T): Util<T> = if (t is B) UtilB() as Util<T> else // ...

据我所知,Kotlin smart cast应该知道utilb()作为util t is b检查。

Java代码和编译器给出了完全相同的结果。

为了为每个实现获得正确的util类,我在伴生对象getUTIL上创建了一个函数,该函数基于泛型类型T的参数为每个实现返回正确的util类,该参数扩展了a:T:a,因此返回类型为util

但是,当我为A的每个派生类编写函数体时,使用Is b检查参数的类型,然后使用utilb()返回正确的util时,Kotlin编译器在返回点给了我一个错误,说utilb不属于util 类型,尽管它应该属于util 类型。

然后,我将utilb强制转换为util,这种方法起作用了,但给了我一个错误“unchecked cast”。根据我的理解,Kotlin smart cast应该能够确定它确实是一个有效的检查型cast(用检查的是b),在运行快速测试后,它也是有效的...

我用Java重写了同样的代码,结果完全一样...

据我所知,这是Java/Kotlin泛型的一个限制。我想知道如何检查这个铸模。有可能吗?

abstract class A
class B : A()
class C : A()

abstract class Util<T : A> {
    abstract fun getName(): String
    companion object {
        fun <T : A> getUtil(t: T): Util<T> = when(t) {
            is B -> UtilB() as Util<T> // warning
            is C -> UtilC() // this event gives an error
            else -> throw IllegalArgumentException("No util for this class.")
        }
    }
}

class UtilB : Util<B>() {
    override fun getName(): String = "B"
}

class UtilC : Util<C>() {
    override fun getName(): String = "C"
}

fun main() {
    val b = B()
    val c = C()
    val utilB = Util.getUtil(b)
    val utilC = Util.getUtil(c)
    println(utilB.getName()) // prints B
    println(utilC.getName()) // prints C
}

共有1个答案

冷正信
2023-03-14

以下是有效的修改版本:

abstract class A
class B : A()
class C : A()

abstract class Util<T : A> {
    abstract fun getName(): String
    companion object {
        fun <T : A> getUtil(t: T): Util<A> = when(t) {    // here return Util<A>
            is B -> UtilB()                               // No need cast
            is C -> UtilC()
            else -> throw IllegalArgumentException("No util for this class.")
        }
    }
}

class UtilB : Util<A>() {                   // Replace B by A
    override fun getName(): String = "B"
}

class UtilC : Util<A>() {                  // Replace C by A
    override fun getName(): String = "C"
}

fun main() {
    val b = B()
    val c = C()
    val utilB = Util.getUtil(b)
    val utilC = Util.getUtil(c)
    println(utilB.getName()) // prints B
    println(utilC.getName()) // prints C
}

但我不确定你走的路是对的。当我看到这个模式时,我看到了密封的类。

下面是一个使用密封类的实现:

sealed class AA {
    class BB : AA()
    class CC : AA()
}
sealed class AAU {
    abstract fun getName():String

    class BBU : AAU() {
        override fun getName()= "BB"
    }

    class CCU : AAU(){
        override fun getName()= "CC"
    }
}

fun getU(aa: AA) =
    when(aa) {
        is AA.BB -> AAU.BBU()
        is AA.CC -> AAU.CCU()
    }

fun main() {
   val bb = AA.BB()
   val cc = AA.CC()
   val bbu = getU(bb)
   val ccu = getU(cc)
   println(bbu.getName())
   println(ccu.getName())
}
sealed class AA {
    class BB : AA()
    class CC : AA()
}

fun getName(aa: AA) =
        when(aa) {
            is AA.BB -> "BB"
            is AA.CC -> "CC"
        }

fun main() {
    val bb = AA.BB()
    val cc = AA.CC()
    println(getName(bb))
    println(getName(cc))
}
 类似资料:
  • 我需要 Kotlin 中的一个集合来仅包含实现给定接口的元素。 例如:包含动物集合的地图: 通过阅读文档、博客和SO问题,我编写了使用Generics in关键字的代码: 现在我想在Test类中添加一个读取“data”内容的方法,例如将其打印到控制台: 如果我这样做,我会遇到编译错误: 我的解决方案是强制我的动物进入一个ArrayList 但是我不确定这是编写这种代码的最好方式。有没有更好的方式告

  • 问题内容: 以下代码在t3行中出现编译错误: 错误消息是: 类型不匹配:无法从对象转换为T 我知道我可以使用强制转换或手动绑定来解决问题,我的问题是: 编译器进行自动绑定是否如此困难,是否会失败? 编辑:添加了错误消息。 编辑:添加了另一个示例如何不会发生该错误。 编辑:删除了第二个示例,因为它令人困惑,使问题更加清楚。 问题答案: 在第一种情况下,您有两个具有名为的类型参数的泛型方法,但是这些类

  • 我有一个gradle 4.1多项目,其中包含一个包含2个子文件夹“api”和“实现”的“项目A”。 多项目使用在主build.gradle的子项目部分中定义的< code>kotlin和< code>java-library插件。实现项目具有对< code>:projectA:api的API依赖性 在api文件夹中,我在“src/main/java”中有kotlin和java文件,在实现项目中,我

  • 因此,我有一些带有这些签名的Java方法(为了简单起见,删除了注释和代码体): 我在Kotlin中有一些代码,它调用了'join'方法: 例如,如果我想用“分隔符”参数调用后一个方法签名,问题就来了: 这段代码无法编译。编译器无法决定调用哪个方法。错误: 错误:(5,13)Kotlin:在未完成类型推断的情况下,无法在以下候选项中进行选择:public open fun join(vararg A

  • 在stackoverflow中还没有讨论的情况下,我遇到了“不兼容类型”编译器错误(例如,为什么这个通用java代码不能编译?)。 我的期望很简单--我调用的是一个模板化方法,它不使用包含类的任何“泛型”类,因此它应该从方法参数中提取模板参数的类型,并且在所有情况下都应该编译--但我得到了“不兼容类型”编译器错误。 我注意到解决这个问题的奇怪方法--在方法参数中向泛型datatype添加“<?ex

  • 这个问题已经被问了很多次了,即使是在经历了所有的解决方案之后,我也无法让hibernate validator工作。 控制器类:- servlet-上下文:- 依赖关系:- 验证类:- 我错过了什么?