2016-05-11 8 views
4

Ich brauche viele Objekte zu speichern, die zu verschiedenen Klassen gehören:Java - Speicher-Objekte in einer Hierarchie, die ihre Klassenvererbung folgt

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

Jetzt muss ich einen Weg finden, alle diese Objekte in einer Art und Weise zu speichern, das ermöglicht mir effizient bekommen alle Objekte, die zu einer bestimmten Klasse gehören und seine geerbt Kind-Klassen. Zum Beispiel dieser imaginären Code

getObjects(ClassA2) 

würde eine Liste aller gespeicherten Objekte zurück, die zu ClassA2 oder ClassA2a gehören.

Ich glaube, eine Baumsammlung von irgendeiner Art wäre geeignet, aber ich kann mir keinen Weg vorstellen, es zu implementieren. Irgendwelche Ideen?


(Hintergrund:. Ich ein einfaches Java-Spiel erschaffe, in denen es gibt Anzahl des Sprites, die ich verwalten müssen, während einige dieses Sprites ähnliche Objekte gemeinsam nutzen Wenn ich für Ereignisse wie Kollisionen zu überprüfen, muß ich Holen Sie alle Objekte, die EnemySprite erweitern und vergleichen Sie ihre Koordinaten mit dem Sprite des Spielers.)

+0

Was soll 'Class1: ChildClass2' bedeuten? – shmosel

+0

Alle Objekte vom Typ ChildClass2 (erweitert Class1). Ich werde versuchen, es klarer zu schreiben. – Brikowski

+0

Die Frage ist jetzt klarer. Habe ich richtig verstanden, was Sie in meiner Antwort vorhatten? – Mifeet

Antwort

3

Mifeet scheint buchstäblich Ihre Frage beantwortet zu haben, aber ich vermute, Sie sollten Sie vorschlagen tun nicht versuchen, zu tun, was. Warum haben Sie nicht einfach eine Hauptliste aller Objekte, die kollidieren könnten, und filtern Sie sie dann mit instanceof?

Dies ist vom Konzept her viel einfacher als das, was Sie tun vorschlägt, und die efficiency impact probably isn't that big. (In der Regel werden Sie wahrscheinlich hören oder das Mantra gehört haben. Versuchen Sie nicht zu früh zu optimieren)

Um ehrlich zu sein, bin ich mir nicht sicher, dass Sie erkennen, dass das Filtern nach Ihnen alle Objektinstanzen seiner Unterklassen auch bringt.

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

Sie haben absolut recht! Ich hatte keine Ahnung, dass instanceof() für Unterklassen funktioniert, also verwende ich etwas, das Ihrer Antwort ähnlich ist - eine einzige Liste aller Objekte durchzugehen und die Ergebnisse zu verengen ist für meine Bedürfnisse mehr als ausreichend. Vielen Dank! – Brikowski

+0

Für eine allgemeinere Lösung, [siehe diese Antwort] (http://stackoverflow.com/a/37174482/5743988) – 4castle

4

Es gibt mehrere Möglichkeiten, wie Sie das erreichen können. B. Zeichenfolgen wie ParentClass1:ChildClass2:ChildClass1: für jedes Objekt erzeugen und sie als Schlüssel für eine oder Trie verwenden, die Sie dann durchlaufen würden.

Hier ist eine einfachere Lösung. Die folgende Klasse enthält eine Zuordnung von der Klasse zu allen Objekten, die sie implementieren. Der einzige Trick ist das Hinzufügen eines Objekts zu allen Eimern, wo es hingehört:

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); 
    } 
} 

Verbrauch:

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

Ich würde die Map beim Iterieren aktualisieren, anstatt eine Wegwerfliste zu erstellen. Wenn Sie eine hellere Map und schnellere Schreibvorgänge wünschen (wenn auch mit langsameren Lesevorgängen), können Sie ein Objekt nur nach seiner eigenen Klasse abbilden und die Hierarchie in 'getByClass()' durchlaufen. – shmosel

+0

Ich stimme dem ersten Punkt völlig zu. Die zweite hängt vom Verwendungsmuster ab, und es liegt an @ Brikowski, sich zu entscheiden. – Mifeet

+0

Was mein spezifisches Problem angeht, habe ich mich für eine einfachere Methode entschieden, aber Ihr Algorithmus beantwortet meine Frage sehr gut. Vielen Dank! – Brikowski

0

Wenn Sie nur Kollisionserkennung wollen, dann würde ich sie auf eine statische Sammlung in der Vorgängerklasse hinzufügen . Dies wäre die effizienteste Lösung.

Wenn Sie alle Nachkommen für eine Klasse möchten, sollten Sie die Reflektions-APIs überprüfen. Ja, man sagt sie seien langsam, aber ich habe Zweifel, ob es genug ist für Dinge, die nicht für jeden Frame berechnet werden. Und für Dinge, die Sie in jedem Frame benötigen, wäre die Traversierung von Bäumen sowieso ineffizient. (@ Miffet Vorschlag von String-Vergleich wahrscheinlich wäre noch langsamer als regelmäßige Reflexion.)

1

Wenn Sie die Objekte in einem List<Object> sind speichern, rufen Class#isInstance() auf jedem Element, das Hinzufügen sie zu einem anderen List wenn isInstance() kehrt 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

* ... das erlaubt mir ** alle Objekte effizient zu erhalten ... * – shmosel

+0

@smoselos Es hängt davon ab, wie viele Objekte wir sprechen. 1000s? Ja – 4castle

+0

Wenn es sich um eine minimale Anzahl von Objekten handelt, hätte OP meiner Meinung nach die Effizienz nicht als Problem betrachtet. – shmosel