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
逆变 。如果
PSuper
是P
的超类型,则任何KFunction1<PSuper, R>
将是KFunction1<P, R>
的子类型。 但是限制会增加P1
只能作为(传入)KFunction1
成员的参数出现。 -
R
通过out
修饰符引入的协方差 。如果
RSub
是KFunction1<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