Возможно, проблема в том, что вы пытаетесь привести IAtom<?, ?>
к Atom
(то есть Atom<Atom, Space>
). Как, черт возьми, система должна знать, что ?
может быть Атомом и Космосом или нет?
Когда вы не знаете, какие типы указывать в месте заполнения дженериков, вы обычно просто отбрасываете все целиком, как в
ISpace spaceSupertype = new Space();
Это генерирует предупреждение компилятора (не об ошибке), но ваш код все равно будет выполняться (хотя, если фактический тип не совместим с приведением типов, вы получите ошибку времени выполнения).
Все это не имеет смысла смотреть, хотя. Вы говорите, что нуждаетесь в строгой типизации, а затем вставляете ?
туда, куда идут типы. Затем вы поворачиваетесь и пытаетесь разыграть их.
Если вам нужно использовать их в Space и Atom, вам, вероятно, стоит использовать их для начала. Если вы не можете этого сделать, потому что в конечном итоге вы собираетесь встраивать другие типы в эти переменные, ваш код все равно сломается, когда вы все равно измените тип среды выполнения, если только вы не используете кучу операторов if / then (как в конец этого комментария).
Правда, если вы делаете такие странные вещи, я думаю, мы смотрим на плохой дизайн кода. Переосмыслите, как вы это структурируете. Может быть, вам нужны другие классы или интерфейсы для выполнения функций, которые у вас есть.
Спросите себя: «Действительно ли мне нужны сильные типы? Что меня приобретает?» Лучше не добавлять поля, так как вы используете интерфейсы. (Имейте в виду, что если доступ к полям осуществляется только через методы, то вы только добавляете методы в открытый интерфейс.) Если он добавляет методы, то использование одиночных интерфейсов IAtom
и ISpace
является плохой идеей, поскольку вы все равно сможете использовать test()
только с этим подтипом. test()
не будет распространяться на другие реализации ISpace
/ IAtom
. Если у всех реализаций, которые вы здесь поместите, есть те же методы, которые вам нужны для test()
, но не у всех реализаций IAtom
/ ISpace
есть их, вам нужен промежуточный подинтерфейс:
public interface IAtom2 extends IAtom
{
[additional methods]
}
Тогда вы можете использовать IAtom2
вместо IAtom
в test()
. Тогда вы автоматически получаете необходимый набор текста и вам не нужны дженерики. Помните, если набор классов имеет общий открытый интерфейс (набор методов и полей), этот открытый интерфейс является хорошим кандидатом на наличие супертипа или интерфейса. Я описываю что-то вроде параллелограмма, прямоугольника, квадрата, где вы пытаетесь пропустить часть прямоугольника.
Если вы не собираетесь перепроектировать, другая идея заключается в том, что вы отбрасываете циклические дженерики и просто выполняете тестирование экземпляра с помощью instanceof
:
if (spaceSupertype instanceof Space)
{
Space space = (Space)spaceSupertype;
...
}
else
...