2016-05-11 2 views
4

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

ClassA {...} 
ClassA1 extends ClassA {...} 
ClassA2 extends ClassA {...} 
ClassA2a extends ClassA2 {...} 
ClassB {...} 

Теперь мне нужно найти способ, чтобы сохранить все эти объекты в пути что позволяет мне эффективно получить все объекты, принадлежащие к определенному классу, и его унаследовал дочерние классы . Например, этот воображаемый код

getObjects(ClassA2) 

будет возвращать список всех сохраненных объектов, которые принадлежат к ClassA2 или ClassA2a.

Я считаю, что какая-то коллекция деревьев была бы подходящей, но я не могу придумать, как ее реализовать. Есть идеи?


(фон:. Я создаю простой Java игру, в которой есть количество спрайтов, что мне нужно управлять, в то время как некоторые из этих спрайтов имеют сходные свойства Когда я проверяю для таких событий, как столкновения, мне нужно получить все объекты, которые расширяют EnemySprite и сравнить их координаты с спрайтом игрока.)

+0

Что означает 'Class1: ChildClass2', который должен обозначать? – shmosel

+0

Все объекты типа ChildClass2 (расширяет Class1). Я постараюсь написать его более четко. – Brikowski

+0

Вопрос теперь понятен. Я правильно понял, что вы намеревались в моем ответе? – Mifeet

ответ

3

Mifeet, кажется, буквально ответил на ваш вопрос, но я подозреваю, что вы не должны пытаться делать то, что вы предлагаете сделать. Почему бы просто не создать основной список всех объектов, которые могли бы столкнуться, а затем отфильтровать его по мере необходимости, используя instanceof?

Это концептуально намного проще, чем то, что вы предлагаете делать, и efficiency impact probably isn't that big. (В общем, вы, вероятно, слышал или слышал мантру:. Не пытаться оптимизировать слишком рано)

Честно говоря, я не уверен, что вы понимаете, что фильтрация для EnemySprite также даст вам все экземпляры объектов ее подклассов.

public class CollisionChecker(){ 

    private List colliders; 

    public CollisionChecker(){  
     colliders = new ArrayList<Object>();  
    } 

    public void addCollider(Object o){ 
     colliders.add(o); 
    } 

    public List<EnemySprite> getEnemySprites(){ 
     List<EnemySprite> enemies = new ArrayList<EnemySprite>(); 
     for (Object o : colliders) 
      if (o instanceof EnemySprite) 
       enemies.add((EnemySprite)o); 
     return enemies;   
    }  
} 
+0

Вы абсолютно правы! Я понятия не имел, что instanceof() работает для подклассов, поэтому я буду использовать что-то похожее на ваш ответ - через один список всех объектов и сужение результатов просто более чем достаточно для моих нужд. Благодаря! – Brikowski

+0

Для более обобщенного решения [см. Этот ответ] (http://stackoverflow.com/a/37174482/5743988) – 4castle

4

Есть несколько способов, как подойти к этому. Можно было бы, например, генерировать строки, такие как ParentClass1:ChildClass2:ChildClass1: для каждого объекта, и использовать их в качестве ключа к TreeMap или Trie, которые вы пройдете.

Вот еще более простое решение. Следующий класс содержит карту от класса ко всем реализующим ее объектам. Единственный трюк добавления объекта для всех ковшей, где она принадлежит:

public class HierarchyMap { 
    private final Map<Class<?>, List<Object>> map = new HashMap<>(); 

    public void add(Object o) { 
     Class<?> clazz = o.getClass(); 
     while (clazz != Object.class) { 
      List<Object> list = map.computeIfAbsent(clazz, c -> new ArrayList<>()); 
      list.add(o); 
      clazz = clazz.getSuperclass(); 
     } 
    } 

    public List<Object> getByClass(Class<?> clazz) { 
     return map.get(clazz); 
    } 
} 

Использование:

public class A { public String toString() { return "A"; } } 
public class B extends A{ public String toString() { return "B"; } } 
public class C extends B { public String toString() { return "C"; } } 
// ... 
HierarchyMap hierarchyMap = new HierarchyMap(); 
hierarchyMap.add(new A()); 
hierarchyMap.add(new B()); 
hierarchyMap.add(new C()); 
System.out.println(hierarchyMap.getByClass(B.class)); 
// prints [B, C] 
+0

Я бы обновил карту во время итерации вместо создания списка бросков. Кроме того, если вам нужна более легкая карта и более быстрая запись (хотя и с более медленными чтениями), вы можете сопоставить объект только своим собственным классом и пересечь иерархию в 'getByClass()'. – shmosel

+0

Я полностью согласен с первым пунктом. Второе зависит от шаблона использования, поэтому решать это нужно @Brikowski. – Mifeet

+0

Что касается моей конкретной проблемы, я решил использовать более простой метод, но ваш алгоритм очень хорошо отвечает на мой вопрос. Спасибо! – Brikowski

0

Если вы просто хотите, обнаружение столкновений, то я хотел бы добавить их к статической коллекции в родительском классе , Это было бы наиболее эффективным решением.

Если вы хотите, чтобы все потомки для класса, вы должны проверить API-интерфейсы отражения. Да, говорят, они медленные, но я сомневаюсь, что это достаточно важно для вещей, которые не вычисляются для каждого кадра. И для вещей, которые вам нужны в каждом обходе дерева кадров, все равно неэффективно. (@ Предложение Miffet по сравнению строк, вероятно, будет еще медленнее, чем обычные отражения.)

1

Если вы храните объекты в List<Object>, вызовите Class#isInstance() по каждому элементу, добавляя их к другим List, если это isInstance() возвращается true.

List<Object> objects = new ArrayList<>(); 

public <T> List<T> getObjects(Class<T> desiredClass) { 
    List<T> desiredObjects = new ArrayList<>(); 
    for (Object o : objects) 
     if (desiredClass.isInstance(o)) 
      desiredObjects.add((T)o); 
    return desiredObjects; 
} 

getObjects(EnemySprite.class); // call it like this 
+0

* ..., что позволяет мне эффективно ** получать все объекты ... * – shmosel

+0

@shmosel Это зависит от того, сколько объектов мы говорим. 1000s? Да – 4castle

+0

Если это минимальное количество объектов, я не думаю, что OP упомянул бы эффективность как проблему. – shmosel

Смежные вопросы