Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - store objects in a hierarchy that follows their class inheritance

Tags:

java

I need to store lots of objects that belong to different classes:

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

Now I need to find a way to store all these objects in a way that allows me to efficiently get all objects that belong to a particular class and its inherited child classes. For example, this imaginary code

getObjects(ClassA2)

would return a list of all stored objects that belong to ClassA2 or ClassA2a.

I believe a tree collection of some sort would be suitable, but I can't think of any way to implement it. Any ideas?


(Background: I am creating a simple java game, in which there's number of sprites that I need to manage, while some of those sprites share similar properties. When I check for events like collisions, I need to get all objects that extend EnemySprite and compare their coordinates with the player's sprite.)

like image 357
Brikowski Avatar asked May 11 '16 21:05

Brikowski


People also ask

What is inheritance hierarchy in Java?

Hierarchical inheritance is one of the types of inheritance where multiple child classes inherit the methods and properties of the same parent class. Hierarchical inheritance not only reduces the code length but also increases the code modularity.

Does Java have hierarchical inheritance?

On the basis of class, there can be three types of inheritance in java: single, multilevel and hierarchical.

What is a class inheritance hierarchy?

Classes are organized into a singly rooted tree structure, called an inheritance hierarchy. Information (data and/or behavior) associated with one level of abstraction in a class hierarchy is automatically applicable to lower levels of the hierarchy.

What is a Java class hierarchy?

In Java, the class hierarchy is tree like. In fact, not only is the hierarchy tree-like, Java provides a universal superclass called Object that is defined to be the root of the entire class hierarchy. Every class that is defined in a Java program implicitly extends the class Object.


2 Answers

There are several ways how to approach this. One would be, e.g., to generate strings like ParentClass1:ChildClass2:ChildClass1: for every object and use them as a key to a TreeMap or Trie which you would then traverse.

Here is a simpler solution, though. The following class contains a map from class to all objects implementing it. The only trick is adding an object to all buckets where it belongs:

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

Usage:

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]
like image 100
Mifeet Avatar answered Sep 26 '22 00:09

Mifeet


Mifeet seems to have literally answered your question, but I suspect you shouldn't be trying to do what you're proposing to do. Why not just have a master list of all objects that might collide, then filter it as needed using instanceof?

This is conceptually a lot easier than what you're proposing to do, and the efficiency impact probably isn't that big. (In general, you will probably hear or have heard the mantra: Don't try to optimize too early.)

To be honest, I'm not sure you realize that filtering for EnemySprite will get you all object instances of its subclasses as well.

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;        
   }     
}
like image 21
Brandon Avatar answered Sep 24 '22 00:09

Brandon