генерации котлина в KFunction1

Предположим, у вас есть два класса 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 

Как вы можете видеть, я получаю доступ к методу TestA класса TestB: TestA :: getIntProp SO. Результатом является экземпляр KFunction1 с общими параметрами <TestA, Int>

Теперь я пытаюсь создать следующую строку кода

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

И он также работает и компилируется, хотя я ожидаю, что будет ошибка компиляции

Это дисперсия generics в Kotlin , ее цель – наложить иерархию типов на общие классы с параметрами, которые сами по себе находятся в иерархии классов.

Класс KFunction1 имеет общие параметры, определенные как <in P1, out R> , P1 с модификатором и 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 .

Поэтому вы сможете назначить KFunction1<PSuper, RSub> переменной типа KFunction1<P, R> .

Это имеет смысл для KFunction1 , потому что любая функция, которая получает аргумент типа PSuper также может получать экземпляр P (но не наоборот), а любая функция, возвращающая экземпляры RSub в одно и то же время, возвращает экземпляры R (но не порока) Versa).


Вы можете просто составить пример, который показывает это поведение:

 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