Any way to inherit from same generic interface twice (with separate types) in Kotlin?

后端 未结 1 556
你的背包
你的背包 2020-12-17 08:24

I have a scenario in my code where I would like a class to implement an interface for two separate types, like this example:

interface Speaker {
            


        
相关标签:
1条回答
  • 2020-12-17 09:05

    Yes, you're missing an important detail of generics implementation on JVM: the type erasure. In a nutshell, the compiled bytecode of classes doesn't actually contain any information about generic types (except for some metadata about the fact that a class or a method is generic). All the type checking happens at compile time, and after that no generic types retain in the code, there is just Object.

    To discover the problem in your case, just look at the bytecode (in IDEA, Tools -> Kotlin -> Show Kotlin Bytecode, or any other tool). Let's consider this simple example:

    interface Converter<T> {
        fun convert(t: T): T
    }
    
    class Reverser(): Converter<String> {
        override fun convert(t: String) = t.reversed()
    }
    

    In the bytecode of Converter the generic type is erased:

    // access flags 0x401
    // signature (TT;)TT;
    // declaration: T convert(T)
    public abstract convert(Ljava/lang/Object;)Ljava/lang/Object;
    

    And here are the methods found in the bytecode of Reverser:

    // access flags 0x1
    public convert(Ljava/lang/String;)Ljava/lang/String;
        ...
    
    // access flags 0x1041
    public synthetic bridge convert(Ljava/lang/Object;)Ljava/lang/Object;
        ...
        INVOKEVIRTUAL Reverser.convert (Ljava/lang/String;)Ljava/lang/String;
        ...
    

    To inherit the Converter interface, Reverser should in order have a method with the same signature, that is, a type erased one. If the actual implementation method has different signature, a bridge method is added. Here we see that the second method in the bytecode is exactly the bridge method (and it calls the first one).

    So, multiple generic interface implementations would trivially clash with each other, because there can be only one bridge method for a certain signature.

    Moreover, if it was possible, neither Java nor Kotlin has method overloading based on return value type, and there would also be ambiguity in arguments sometimes, so the multiple inheritance would be quite limited.

    Things, however, will change with Project Valhalla (reified generics will retain actual type at runtime), but still I wouldn't expect multiple generic interface inheritance.

    0 讨论(0)
提交回复
热议问题