在kotlin中创建一个随机class的对象

Create an object of random class in kotlin

我在高中学习了 java 和 python,我对 python 感到非常自在。最近开始学习kotlin,主要是为了好玩(定义函数的关键字是fun所以一定是一门有趣的语言对吧),但是有点小问题

假设我有一个 classes 的棋子层次结构:

abstract class Piece {
    ...
}

class Rook : Piece() {
    ...
}

class Bishop : Piece() {
    ...
}
.
.
.

我正在从用户那里获取输入来生成板,所以如果用户键入 r,我需要创建一个 Rook 对象,如果他键入 b,我需要创建一个 Bishop 等等

在python中,我可能会使用一个字典将输入字符串映射到相应的class,这样我就可以创建一个对象正确的类型:

class Piece:
    ...


class Rook(Piece):
    ...


class Bishop(Piece):
    ...
.
.
.


input_map = {
    'r': Rook,
    'b': Bishop,
    ...
}

s = input_map[input()]()  # use user input as key and create a piece of the correct type

当我发现这个模式时,我真的很惊讶。在 java 中,我不得不使用一个 switch case 或一堆 if else if 来实现相同的结果,这不是世界末日,特别是如果我将它抽象成一个单独的函数,但它是不如 python 方法好。

我想在 kotlin 中做同样的事情,我想知道 kotlin 是否有类似的模式,因为它是一种像 python 这样的现代语言(我知道,我知道,python不是新的,但我认为它非常现代)。我尝试在线查看,但似乎无法像在 python.[= 中那样将 class(class,而不是对象)存储在变量或地图中20=]

我错了吗?我可以在 kotlin 中使用类似的模式还是必须退回到 when 语句(或表达式)?

如果我没记错的话,在 java 中可以使用反射实现类似的模式。我从来没有深入学习 java 中的反射,但我知道这是一种动态使用 classes 的方法,我可以在 python 中免费做到这一点。我还听说在 java 中,反射应该作为最后的手段使用,因为它效率低下,如果你理解我的意思,它被认为是“黑魔法”。这是否意味着我需要使用反射来在 kotlin 中实现该结果?如果是的话,是否推荐在kotlin中使用反射,效率高吗?

我想知道如何解决这个问题,我接受多个答案和我没有想出的其他解决方案。提前致谢。

是的,您可以对 Kotlin 使用类似的方法。 Kotlin 有很多特性并且支持反射。让我写一个关于你的问题的例子。

首先创建将由用户输入生成的 classes。

abstract class Piece

class Rook : Piece()
class Bishop : Piece()

创建您的 class 地图

val inputMap = mapOf(
        "r" to Rook::class.java,
        "b" to Bishop::class.java
)

使用 newInstance 函数创建您想要的实例。如果您的输入映射不包含您提供的密钥,那么它将 return null.

    val rook = inputMap["r"]?.newInstance()
    val bishop = inputMap["b"]?.newInstance()
    
    // null
    val king = inputMap["k"]?.newInstance()

您也可以编写自定义扩展来创建新对象。

    fun <T> Map<String, Class<out T>>.newInstance(key: String) = this[key]?.newInstance()

    // Create an instance with extension function
    inputMap.newInstance("r")

这可以在没有反射的情况下完成。

您可以将输入字符映射到构造函数:

val pieceConstructorsByKeyChar = mapOf(
    'r' to ::Rook,
    'b' to ::Bishop,
    // etc.
)

从地图中获取值可为您提供一个可为空的值,因为您提供的键可能不在地图中。也许这很好,如果当你使用它时你可能会传递一个玩家输入的可能不受支持的角色。然后你可能会通过告诉玩家再试一次来处理 null

val piece: Piece? = pieceConstructorsByKeyChar[keyPressed]?.invoke()

或者,如果您在检查它是一个有效的击键后进行查找,您可以安全地使用 !!

val piece: Piece = pieceConstructorsByKeyChar[keyPressed]!!()