假设您有两个类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 结果是具有通用参数的KFunction1的实例&lt; TestA,Int&gt;
现在我尝试创建下一行代码
var getter2: KFunction1<TestA, Int> = TestB::getIntProp
它也可以工作和编译,而我希望会有编译错误
答案 0 :(得分:5)
这是generics variance in Kotlin,其目的是在具有类层次结构的参数的泛型类上强加类型安全层次结构。
类KFunction1
的通用参数定义为<in P1, out R>
,P1
定义为in
修饰符,R
定义为out
修饰符。这意味着将会:
由P1
修饰符引入的 in
的逆转。
如果KFunction1<PSuper, R>
是KFunction1<P, R>
的超类型,则任何PSuper
都将是P
的子类型。但是会增加限制,P1
只能作为(传入)KFunction1
成员的参数出现。
由R
修饰符引入的 out
的协方差。
如果KFunction1<P, RSub>
是KFunction1<P, R>
的子类型,则任何RSub
都是R
的子类型。此处R
将受到限制:它只能用作KFunction1
成员的返回值(已通过)。
因此,您可以将KFunction1<PSuper, RSub>
分配给KFunction1<P, R>
类型的变量。
这对KFunction1
有意义,因为任何接收类型为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