Java - структура данных, содержащая набор различных подклассов одного и того же суперкласса.

Мне нужна какая-то структура данных, которая может содержать разнородные подклассы одного и того же суперкласса, все из которых я реализовал сам.

Пока что я пытаюсь получить ArrayList<SuperClass> list = new ArrayList<SuperClass>();, а затем я предполагаю, что смогу преобразовать каждый слот списка в любой из подклассов, но это не так хорошо работает.

Мне нужен эффективный способ сделать вышеупомянутое.

Спасибо!


person George K.    schedule 04.11.2012    source источник
comment
Хм. Что именно не работает?   -  person Vlad    schedule 05.11.2012
comment
@BheshGurung на самом деле должен быть Collection, а не List   -  person Woot4Moo    schedule 05.11.2012


Ответы (1)


Вы можете сделать это с любой существующей структурой данных, я бы рекомендовал List или Set. Например:

Collection<Super> supers = new ArrayList<Super>();  

Теперь, когда вы говорите это:

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

Это неверное предположение. Коллекция будет содержать любой объект, который расширяет Super, однако вы не можете произвольно преобразовать каждый элемент во что угодно. Вам нужно будет выполнить тест instanceof для каждого элемента, если вы ищете функциональность такого типа, пример ниже:

for(Super currentSuper : supers)  
{  
    if(currentSuper instanceof SubA)  
    {  
         SubA subA = (Suba) currentSuper);  
         // do stuff with subA
    }  
    else if(currentSuper instanceof SubB)  
    {  
         SubB subB = (SubB) currentSuper);  
         // do stuff with subB
    } 
}  

Объем по мере необходимости.

Теперь по поводу Влада:

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

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

for(Super currentSuper : supers)  
{  
    currentSuper.doSomethingNifty();
}  
person Woot4Moo    schedule 04.11.2012
comment
... и гораздо лучшим дизайном было бы не проверять, что такое фактический класс, а просто вызывать виртуальный метод, который в любом случае будет делать правильные вещи. - person Vlad; 05.11.2012
comment
@Vlad Вы имеете в виду, как в C#, где вы можете объявить функцию virtual, или это что-то другое? - person Woot4Moo; 05.11.2012
comment
да. Кстати, в Java методы по умолчанию виртуальные, в отличие от С#. - person Vlad; 05.11.2012
comment
Полезно знать о виртуале. Теперь, в другом примечании, тест instanceof явно используется (в данном случае), если есть что-то особенное, что нужно сделать с объектом. Например, представьте себе сценарий, в котором вы хотите выбросить IllegalArgumentException во время обработки, если кто-то подсунул туда MyDangerousSubclass. Это было бы очень удобно, особенно в тех случаях, когда вы хотите предотвратить выполнение неизвестных подклассов. - person Woot4Moo; 05.11.2012
comment
@Vlad, разве твой первый комментарий не станет отличным ответом на этот вопрос? - person mkl; 05.11.2012
comment
@mkl его комментарий не отвечает необходимости instanceof - person Woot4Moo; 05.11.2012
comment
@mkl: ну, исходный вопрос просто спрашивает, можно ли упаковать объекты в контейнер, а не о том, как с ними работать. Таким образом, комментарий больше относится к примеру в конце этого ответа. - person Vlad; 05.11.2012
comment
Я обновил свой ответ, чтобы предоставить другой пример, предложенный Владом. - person Woot4Moo; 05.11.2012
comment
Думаю, в хорошем дизайне нужно instanceof очень редко. Пример: если ваш цикл применяет разные процедуры рисования для каждого из типов объектов, почему бы не упаковать соответствующий код в виртуальный метод Draw, чтобы ваш цикл выглядел как for(Super s : supers) s.Draw();? (Ну, этот комментарий относится к вашему последнему обновлению ответа.) - person Vlad; 05.11.2012
comment
@Vlad: Чтобы решить эту проблему, мне нужно иметь возможность упаковывать разные объекты в контейнер, а также иметь возможность работать с каждым из конкретных свойств/методов разных объектов. - person George K.; 05.11.2012
comment
@Влад, согласен. Однако как насчет сценария, в котором у вас есть общий API, который люди могут расширить ваш Super класс, и у вас есть white list известных Supers . В чем в таком случае может быть конструктивный недостаток? Я спрашиваю, потому что мне любопытно. Ограничение Super должно быть расширено по желанию, и оно может быть расширено, чтобы быть вредоносным. - person Woot4Moo; 05.11.2012
comment
В этом есть ответ на вопрос. Но что касается использования instanceof и актерского состава, я полностью согласен с @Vlad. - person Bhesh Gurung; 05.11.2012
comment
@George: ну, зачем тебе низкоуровневый доступ к свойствам? Может быть, вам нужно упаковать функционал в виртуальные методы? - person Vlad; 05.11.2012
comment
@Woot4Moo: насчет вредоносных расширителей, ну, я бы предпочел спроектировать так, чтобы список содержал только доверенные объекты (проверять при вставке + не позволять другим изменять мой список), чтобы мне не нужно было перепроверяйте каждый раз, когда я использую список. - person Vlad; 05.11.2012
comment
@Vlad Влад - я исправлен: мне нужен только регулярный доступ к каждому из конкретных методов подкласса - person George K.; 05.11.2012
comment
@ Влад Я понимаю суть проблемы, так что насчет предварительного добавления кода проверки в список. Это код, который меня больше всего интересует, независимо от того, к какой части API он относится. - person Woot4Moo; 05.11.2012
comment
@Woot4Moo: Ну, я бы сделал следующее: создайте непубличный TrustedSuper extends Super, чтобы вы могли фактически объявить supers список TrustedSuper, а не только Super. Поскольку TrustedSuper не является общедоступным, никакие другие пакеты не могут быть получены из него. - person Vlad; 05.11.2012
comment
@Woot4Moo Очевидно, Владу пришлось бы потратить на это несколько слов, но его намек, по сути, является ответом на вопросы, которые следовали задать. За исключением упомянутых соображений безопасности (и в этом случае дизайн, не включающий никаких подклассов, был бы еще лучше), следует избегать явного приведения типов. - person mkl; 05.11.2012