如何在列表中发送和接收通用类型的对象

时间:2019-05-30 13:35:40

标签: kotlin

我正在尝试创建一个类,该类通过一个接口具有两个重写函数。接口将采用通用类型,我希望函数可以简单地进行转换。

但是,当我创建这些对象的多个并将它们放入列表并单数访问它们时,我已经能够做到这一点,然后应将通用类型作为输入的函数会产生错误:{{1 }}

换句话说:

Type mismatch: inferred type is Any but Nothing was expected

这在首次实施时确实有效:

interface ConverterInterface<T>{
    fun sender(value: T): ByteArray
    fun receiver(bytes: ByteArray): T
}

但是,我想存储这些对象的列表并在以后访问。

class TestClass {
    val objA = object: ConverterInterface<String>{
        override fun sender(value: String): ByteArray {
            //...
        }

        override fun receiver(bytes: ByteArray): String {
            //...
        }
    }
}

我必须对列表类型使用通配符fun test(){ val testList: List<ConverterInterface<*>> = listOf(objA) // This works testList[0].receiver(byteArrayOf()) // This does not testList[0].sender("") /* Out-projected type 'ConverterInterface<*>' prohibits the use of 'public abstract fun sender(value: T): ByteArray defined in ConverterInterface */ } ,因为如果尝试使用*,则会收到类型推断失败错误。为了使它起作用,我可以将类型设置为Any,但这不能解决任何问题,只会使out Any函数起作用。

我觉得我想做的事情可能无法实现。简而言之,我希望无需进行类型转换即可访问这些功能。

2 个答案:

答案 0 :(得分:1)

我认为您必须在这里进行一些重新设计。编译器会警告您代码中存在严重的类型安全问题,如果您未正确修复它,它很可能会再次咬住您。

您有List个转换器,但您无法说出每个转换器可以转换的内容;每个人都为{em> some 类型ConverterInterface<T>实现T,但是您不知道列表中任何特定项目的T是什么。

testList[0](假设列表中至少包含一项)可以实现ConverterInterface<String>ConverterInterface<Int>ConverterInterface<Map<URL, LinkedList<LinearGradientPaint>>或其他任何方法。因此,testList[0].realSender("")并不安全,因为它可能不接受字符串。

这就是编译器抱怨的原因;它对所涉及的类型一无所知,因此必须假设最坏的情况,并禁止调用。否则,当转换器无法处理您传递的参数类型时,您将在运行时冒ClassCastException的风险。

更糟糕的是,由于类型擦除,您也无法在运行时找到该类型。 (在运行时,编译器完成魔术之后,只有一个简单的ConverterInterface。)

顺便说一句,realSender()的答案并不能解决这个问题,只是告诉编译器关闭它。它在运行时仍然会咬你。

因此,我认为您需要更仔细地考虑您要在此处实现的目标。

为什么要将这些转换器存储在列表中,为什么需要以这种方式访问​​它们?

如果您知道每个实现都可以接受String,则将列表设为List<ConverterInterface<String>>:编译器将确保列表中的所有内容都可以使用String,然后可以安全地将String传递给任何列表中的转换器。

但是,如果列表中可能包含不同类型的转换器,那么您如何知道正在查看的转换器可以采用任何特定类型?即使该代码现在可以使用,仍然存在稍后会在列表中插入多余项并弄乱内容的风险。因此,您必须另辟track径。而另一种方式可能会为您提供更好的(类型安全)访问方式。

答案 1 :(得分:0)

我不确定这是否是一个好的解决方案,但这是我想出的。我创建了一个抽象类,该类不仅实现了该接口,而且还为发件人提供了预定义的函数,该函数在内部强制转换为T

interface ConverterInterface<T>{
    fun sender(value: T): ByteArray
    fun receiver(bytes: ByteArray): T
}

abstract class TestClass<T> : ConverterInterface<T>{
    fun realSender(value: Any): ByteArray{
        @Suppress("UNCHECKED_CAST")
        return sender(value as T)
    }
}

val testObj = object: TestClass<String>(){
    override fun sender(value: String): ByteArray {
        return byteArrayOf()
    }
    override fun receiver(bytes: ByteArray): String {
        return ""
    }

}

val testList: List<TestClass<*>> = listOf(testObj)

fun a(){
    testList[0].realSender("")
    testList[0].receiver(byteArrayOf())
}

我知道该函数现在可以接受放入其中的任何内容,并且这可能会导致异常,但是到目前为止,我只能将其作为解决方案。另外,至少就我而言,该类的函数除其泛型外不应接收任何其他信息,因此传入的其他类型的值确实是个例外。