Ограничение универсальных параметров различными типами в Java - PullRequest
4 голосов
/ 12 мая 2019

Я не помню правильное название этого, поэтому я не могу Google это, поэтому я спрошу это на примере, так что это будет немедленно позвонить в звонок.

Это дляJava.

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

public interface DBInterface<T, E> {
    public int delete(T element);
}

Моя проблема в том, что когда я пытаюсь перегрузить такую ​​функцию:

public interface DBInterface<T, E> {
    public int delete(T element);
    public int delete(E example);
}

IDE, жалующаяся на T, может beign так же, как E, поэтому он думает, что я объявляю один и тот же метод дважды (потому что, фактически, T может быть тем же, что и E в этом объявлении).

Мои вопросы:

  1. Как это называется?Я хочу переписать вопрос, используя правильную терминологию, чтобы он стал более полезным для других в будущем
  2. Как я могу объявить T и E в интерфейсе, чтобы гарантировать, что они не будут одного типа?

Примерно так:

public interface DBInterface<T, E != T> {
    public int delete(T element);
}

Я делаю это прямо сейчас, разграничивая подобные легальные типы.Это правильный путь?Есть ли способ разрешить ЛЮБОЙ объект, КРОМЕ другого предоставленного?:

public interface DBInterface<T extends DatabaseObject, E> {
}

1 Ответ

2 голосов
/ 12 мая 2019

Есть проблема, потому что компилятор должен использовать стирание параметризованных типов для ваших методов. Так как T и E не попадают в среду выполнения, компилятор систематически заменяет типы параметров вашего метода.

В соответствии с руководством (отметьте this и this ), параметры неограниченного типа заменяются на Object, и ограничения применяются для параметров ограниченного типа. Это означает, что ваши сигнатуры метода скомпилированного интерфейса выглядят так:

public interface DBInterface {
    public int delete(Object element);
    public int delete(Object example);
}

И ваша вторая версия:

public interface DBInterface<T extends DatabaseObject, E> {
    public int delete(DatabaseObject element);
    public int delete(Object example);
}

Я полагаю, что это делает проблему очевидной для вашего первого фрагмента кода.

Как я могу объявить T и E в интерфейсе, чтобы гарантировать, что они не будут одного типа?

Этот вопрос не может принять безусловный ответ. Фактический ответ зависит от значения T и E. Например, не имеет смысла предлагать, чтобы эти параметры типа были ограничены по-разному, потому что в некоторых случаях это может не иметь смысла.

С учетом вышесказанного вы должны рассмотреть вопрос о переименовании методов: я не могу вспомнить DBInterface с двумя одинаково типизированными параметрами, которые не играют разных ролей. Например, методы могут быть:

public int deleteById(T element);
public int deleteByKey(E key);

Другими словами, если бы мы забыли об однобуквенном соглашении об именах общих типов, что бы вы назвали параметрами вашего типа?

public interface DBInterface<IdColumnType, PKColumnType> {}

Я не понимаю, почему это не должно применяться к именам ваших методов, вы должны признать, что, в конце концов, вы разрешили своим пользователям передавать один и тот же класс для обоих аргументов типа ... (то есть что технически у вас все еще есть проблема, даже если компилятор не выполняет стирание типа)

...