如何使用反射和接口调用 Kotlin 伴随对象函数

How to call Kotlin companion object function using reflection and interface

假设我有以下接口:

interface Fooable {
    fun foo()
}

该接口由命名伴随对象实现;例如:

class Impl1 {
    companion object Foo : Fooable {
        fun foo() { ... }
    }
}

class Impl2 {
    companion object Foo : Fooable {
        fun foo() { ... }
    }
}

我希望能够将每个 Impl class 的名称映射到一个 Fooable 实例(因为伴随对象总是单例实例);例如:

fun mapImplToFooable(): Map<String, Fooable> = mapOf(
    "Impl1" to Impl1.Foo,
    "Impl2" to Impl2.Foo
)

然后我可以调用它;例如:

val map = mapImplToFooable()
map["Impl1"]!!.foo()

我想要的是能够使用反射创建地图,而不是硬编码,假设每个 Impl 都有一个 companion object Foo : Fooable { ... }

到目前为止,我所拥有的是一个能够在一个包和子包中找到所有 classes 的函数:

fun findAllClasses(): List<Class<*>> { ... }

由此,我成功走到了这一步:

function mapImplToFooable(): Map<String, Fooable> {
    return findAllClasses()
        .filter { Fooable::class.java.isAssignableFrom(it) }
        .map { clazz -> it.name to clazz } // This is a problem...
        .toMap()

问题是 clazzClass<Fooable> 而不是 Fooable 的实例(在每种情况下,都是伴随对象)。

如何获取伴随对象实例,而不仅仅是一个 Class<Fooable>

使用 Kotlin 反射 API(而不是 Java),这样您就可以访问 objectInstance:

fun mapImplToFooable(): Map<String, Fooable> =
    findAllClasses()
        .filter { 
            Fooable::class.java.isAssignableFrom(it) &&
            it != Fooable::class.java // you should also check this if findAllClasses can return Fooable
        }
        .associate { // .map { ... }.toMap() can be simplified to associate
            // you should get the declaring class's name here
            clazz -> clazz.declaringClass.name to clazz.kotlin.objectInstance as Fooable 
        }