KFunction1中的kotlin泛型

假设你有两个类TestA和TestB。 假设TestA扩展了TestB:

public class TestB { private int intProp; public int getIntProp() { return intProp; } public void setIntProp(int intProp) { this.intProp = intProp; } } public class TestA extends TestB { private String strProp; public String getStrProp() { return strProp; } public void setStrProp(String strProp) { this.strProp = strProp; } } 

现在我创建下一行代码:

 var getter1: KFunction1<TestA, Int> = TestA::getIntProp 

正如你所看到的,我从TestB的TestA类访问方法:TestA :: getIntProp SO,结果是KFunction1的实例,泛型参数<TestA,Int>

现在我尝试创建下一行代码

 var getter2: KFunction1<TestA, Int> = TestB::getIntProp 

而且它也可以工作和编译,而我预计会有编译错误

这是Kotlin中的泛型变化 ,其目的是在泛型类上强加类型安全的层次结构,这些泛型类本身具有类层次结构的参数。

KFunction1类具有泛型参数,定义为<in P1, out R>P1带有修饰符, R带有out修饰符。 这意味着将会有:

  • in修饰符中引入的P1 逆变

    如果PSuperP的超类型,则任何KFunction1<PSuper, R>将是KFunction1<P, R>的子类型。 但是限制会增加P1只能作为(传入) KFunction1成员的参数出现。

  • R通过out修饰符引入的协方差

    如果RSubKFunction1<P, R>的子类型, KFunction1<P, R>任何KFunction1<P, RSub>将是KFunction1<P, R>的子类型。 这里R将是有限的:它只能被用作KFunction1成员的返回值(传出)。

因此,您可以将KFunction1<PSuper, RSub>分配给KFunction1<P, R>类型的变量。

这对于KFunction1是有意义的,因为任何接收PSuper类型参数的PSuper也可以接收P一个实例(反之亦然),并且在同一时间返回RSub实例的任何函数都会返回R实例反之亦然)。


你可以简单地写一个显示这个行为的例子:

 class Invariant<T> { fun f(i: Int): T { throw Exception() } // OK fun f(t: T): Int { throw Exception() } // OK } class Contravariant<in T> { fun f(i: Int): T { throw Exception() } // error, T cannot be returned fun f(t: T): Int { throw Exception() } // OK, T is parameter type } class Covariant<out T> { fun f(i: Int): T { throw Exception() } // OK, T is returned fun f(t: T): Int { throw Exception() } // error, T cannnot be parameter type } open class Base class Derived: Base() val i1: Invariant<Base> = Invariant<Derived>() // error val i2: Invariant<Derived> = Invariant<Base>() // error val n1: Contravariant<Base> = Contravariant<Derived>() // error val n2: Contravariant<Derived> = Contravariant<Base>() // OK val v1: Covariant<Base> = Covariant<Derived>() // OK val v2: Covariant<Derived> = Covariant<Base>() // error