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

时间:2021-02-21 17:25:57

标签: kotlin reflection polymorphism

我在高中学习了 Java 和 Python,并且对 Python 非常熟悉。我最近开始学习kotlin,主要是为了好玩(定义函数的关键字是fun,所以它必须是一种有趣的语言,对吧),但我有一个小问题。

假设我有一个国际象棋类的层次结构:

abstract class Piece {
    ...
}

class Rook : Piece() {
    ...
}

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

我正在接受用户的输入来生成板,所以如果用户输入 r,我需要创建一个 Rook 对象,如果他输入 b,我需要创建 Bishop

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

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 中那样将类(类,而不是对象)存储在变量或映射中。

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

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

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

2 个答案:

答案 0 :(得分:3)

这无需反思即可完成。

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

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

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

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

或者,如果您在已经检查它是有效击键之后进行查找,则可以安全地使用 !!

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

答案 1 :(得分:0)

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

首先创建将通过用户输入生成的类。

abstract class Piece

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

创建您的班级地图

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

使用 newInstance 函数创建您想要的实例。如果您的输入映射不包含您提供的键,则它将返回 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")