【问题标题】:How to map a generic class to a generic array of the same class in Kotlin如何将泛型类映射到 Kotlin 中同一类的泛型数组
【发布时间】:2020-07-08 15:41:33
【问题描述】:

我想知道,如何在 Kotlin 中将泛型类映射到相同类型的泛型数组。

给定以下课程:

class <T> MyClass(val type : Class<T>) {
  fun new() = type.newInstance()
}

我想要类似的东西:

class MyOtherClass {
  val map = Map<Class<T>, MyClass<T>>

  inline fun <reified T> get() : MyClass<T> {
    if(T::class.java in map) {
      return map[T::class.java]
    } else {
      val newInstance = MyClass(T::class.java)
      map[T::class.java] = newInstance
      return newInstance
    }
  }
}

但是,这不起作用,因为:

  • T 不能在 MyOtherClass 中使用
  • 在 MyOtherClass 中将 T 更改为 Any 会引发类型推断错误,需要 Any 但我们有 T
  • 更改为 Any 也不起作用
  • 更改为确实有效,但会发出警告,“return map[T::class.java]”是未经检查的演员表

我不知道如何以及是否可以这样写,但从逻辑的角度来看,我想实现以下目标:

  • 有一个通用管理器类,可以为给定类型执行某些操作(=上面的 MyClass)
  • 有另一个类按类型缓存此类管理器类。如果存在给定类型的管理器,则应使用该管理器而不是创建新管理器
  • 因此,我想将一个类型映射到同一类型的经理

如前所述,我有一种编写方法,如下所示,但我想避免强制转换警告,因为在我看来它是无效的,因为地图应该告诉编译器获取 X 类型的东西将返回X 类型的 MyClass。

class MyOtherClass {
  val map = Map<Class<out Any>, MyClass<out Any>>

  inline fun <reified T:Any> get() : MyClass<T> {
    if(T::class.java in map) {
      return map[T::class.java] as MyClass<T>
    } else {
      val newInstance = MyClass(T::class.java)
      map[T::class.java] = newInstance
      return newInstance
    }
  }
}

感谢大家的帮助!

【问题讨论】:

  • 将您的地图更改为val map = mutableMapOf&lt;Class&lt;*&gt;, MyClass&lt;*&gt;&gt;(),然后以您的方法return map[T::class.java] as MyClass&lt;T&gt; 为我工作
  • 感谢您的快速回复!你没有收到未经检查的演员表的警告吗?至少这是我得到的,但也许我做的事情与你不同而“*”到底是什么?我只知道 Kotlin 中的 Any 和 Nothing。
  • * 是一个通配符,因此您不知道自己在使用什么。未经检查的演员表是一个后果,据我所知,你无法解决
  • 是的,警告是合法的,因为它周围不再有编译时类型安全性。您必须确保只存储合理的映射,然后您可以取消警告。你基本上是在告诉工具“我知道我在这里做什么,这是安全的。”
  • 谢谢你们!我明天会写一个干净的答案然后关闭它

标签: java kotlin generics


【解决方案1】:

正如 Lino 在开篇文章中提到的,没有警告是不可能的,因为通用信息 T 丢失了Something。

此外,* 可以用作 Kotlin 中的通配符,因此以下方法有效(取自真实代码):

inline fun <reified T> componentManager(): ComponentManager<T> = componentManager(T::class.java)

    @Suppress("UNCHECKED_CAST")
    fun <T> componentManager(type: Class<T>): ComponentManager<T> {
        return when {
            componentManagers.containsKey(type) -> {
                componentManagers[type] as ComponentManager<T>
            }
            else -> {
                val manager = ComponentManager(initialEntityCapacity, type)
                addListener(manager)
                componentManagers.put(type, manager)
                manager
            }
        }
    }

感谢 Lino!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2016-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多