Комплексные родовые комбинации - PullRequest
0 голосов
/ 31 марта 2009

Представьте себе универсальный класс MySet, который поддерживает родительский экземпляр MySet и дочерний экземпляр MySet. Идея состоит в том, что родитель должен иметь возможность хранить надмножество T, а потомок - подмножество. Итак, учитывая следующий пример, рассмотрим следующую проблему:

class MySet<T> {

  MySet<? extends T> child; 

  void doStuff (Collection<? extends T> args) {
    child.doStuff(this, args);
  }

}

РЕДАКТИРОВАТЬ: фиксированный вопрос и пример кода для отражения реальной проблемы

Теперь дочерний шаблон <T> может быть более строгим, чем родительский <T>, поэтому родитель должен передать в Collection <X>, где <X> соответствует дочернему <T>. Имейте в виду, что эта цепочка parent-> child может быть произвольно длинной. Есть ли способ упорядочить дженерики так, чтобы parent.doStuff (...) скомпилировался, т. Е. Чтобы его можно было вызывать только с аргументами самого строгого потомка?

Это будет означать, что компилятор java будет передавать общую информацию по всей цепочке parent-> child, чтобы определить допустимые аргументы для doStuff, и я не знаю, есть ли у него такая возможность.

Это единственное решение, гарантирующее, что дети не могут быть более строгими, чем их родители, использующие дженерики (т. Е. MySet <T> child; вместо MySet <? extends T>) и позволяющие детям быть более строгими, чем их родители в других местах кода.

Ответы [ 2 ]

1 голос
/ 01 апреля 2009

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

Есть ли способ устроить дженерики, так что parent.doStuff (...) будет компилироваться, т. е. чтобы он мог только быть вызван с аргументами этого самый строгий ребенок?

Это будет означать, что компилятор Java будет передавать общую информацию все путь вверх по цепочке родительский-> дочерний определить, какие допустимые аргументы чтобы doStuff мог быть, и я не знаю если у него есть такая возможность.

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

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

Так что нет, если фактический конечный тип не известен (и указан, возможно, с помощью аргумента второго типа) заранее, компилятор не сможет вам там помочь.

То, что вы можете (и должны делать imo), это придерживаться того, что вы только что написали (что должно прекрасно скомпилироваться), и передать ему аргумент, который может быть небезопасным. Независимо от того, проверяете ли вы это самостоятельно или разрешаете JVM вызвать ClassCastException, остается вопрос выбора.

0 голосов
/ 01 апреля 2009

Представленный код, похоже, не имеет смысла.

Рассмотрим

 MySet<String> c = ...;
 MySet<Object> p = new MySet<Object>(c);
 Collections<Integer> ints = ...;
 p.doStuff(ints);

Это будет звонить c.doStuff(???, ints). ints имеет тип Collection<Integer>, но вызываемый абонент требует doStuff(Collection<? extends String>).

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