Используйте подтип класса в универсальном классе - PullRequest
2 голосов
/ 08 марта 2019

Я пытаюсь использовать универсальный тип класса в другом классе, который использует этот:

Kotlin

class Callback <O> () 

class Controller <E> (callback: E) where E: Callback<O> {
    fun foo1 (a: O) {...}
    fun foo2 (): O {...}
}

Java

class Callback <O> {}

class Controller <E extends Callback<O>> {
    Controller(E callback) {}
    public void foo1(O a) {...}
    public O foo2() {...}
}

Простое решение - объявить оба типа E и O в классе Controller следующим образом:

Kotlin

class Controller <E, O> (callback: E) where E: Callback<O> { ... }

Java

class Controller <E extends Callback<O>, O> { ... }

Однако я хочу не объявлять оба типа в конструкторе, потому что информация повторяется, и она не такая красивая.

Редактировать

Мне нужен тип E в конструкторе, потому что мне нужно определить такие функции, как:

class StringCallback: Callback<String>() { ... }

fun example(callbackParam: Controller<StringCallback>) { ... }

Я хочу, чтобы объект callbackParam использовал мой определенный StringCallback, а не какой-либоCallback<String>.

И помните, что мне также необходим тип O в классе Controller для работы с этим типом.Могу ли я «извлечь» или «вывести» его, не объявив его в универсальном конструкторе?

[@ LppEdd с вашего разрешения, я буду использовать ваш класс :)]

Есть идеи?

Заранее спасибо !!

Ответы [ 3 ]

2 голосов
/ 08 марта 2019

Вам не нужно знать тип Callback, просто его универсальный параметр E.

Таким образом, вы можете объявить свой класс в Kotlin следующим образом:

class Controller<O>(callback: Callback<O>) { ... }

А в Java вот так:

public class Controller<O> {
    public Controller(Callback<O> callback) { ... }
}

Объявление типа Callback универсальным имеет смысл только в том случае, если вы позволите вызывающей стороне вашего контроллера явно взаимодействовать с обратным вызовом. Но из заданного вами кода вы просто возвращаете или принимаете значения от / до обратного вызова.

2 голосов
/ 08 марта 2019

Что вы можете сделать, это

class Controller<E> {
    private final Callback<E> callback;

    Controller(final Callback<E> callback) {
        this.callback = callback;
    }

    public void foo1(final E a) { callback.set(a); }
    public E foo2() { return callback.get(); }
}

Пример:

final Controller<String> stringController = new Controller<>(new Callback<>());

Это потому, что вы уже знаете, что примете Callback<?>.
Нет необходимости использовать E extends Callback. Но продолжайте читать

Это

Controller(final Callback<? extends E> callback)

означает, что конструктор будет принимать каждый тип, который является подтипом Callback<E>

class StringCallback extends Callback<String> { ... }
class IntegerCallback extends Callback<Integer> { ... }

final Controller<String> c1 = new Controller<>(new StringCallback());
final Controller<Integer> c2 = new Controller<>(new IntegerCallback());
1 голос
/ 08 марта 2019

Вы можете сократить код:

class Controller<E : Callback<O>, O> (callback: E) { .. }

Но это не даст вам возможности избавиться от второго универсального параметра.Вы используете тип O в функциях вашего класса.

Вы можете попытаться сказать class Controller<E: Callback<*>> или class Controller<E : Callback<Any>>, если вам не нужен фактический тип O в коде класса Controller.

Использование Callback<Any> может потребовать объявления параметров типа Callback с дисперсией.В Kotlin каждый определяет дисперсию на уровне декларации.Подробнее см. https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...