簡體   English   中英

Java - 將對象存儲在遵循其類繼承的層次結構中

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

我需要存儲許多屬於不同類的對象:

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

現在我需要找到一種方法來存儲所有這些對象,使我能夠有效地獲取屬於特定類及其 繼承 子類的所有對象。 例如,這個虛構的代碼

getObjects(ClassA2)

將返回屬於ClassA2或ClassA2a的所有存儲對象的列表。

我相信某種樹集合是合適的,但我想不出任何實現它的方法。 有任何想法嗎?


(背景:我正在創建一個簡單的java游戲,其中有許多精靈需要管理,而其中一些精靈共享相似的屬性。當我檢查碰撞等事件時,我需要獲取所有擴展EnemySprite和將他們的坐標與玩家的精靈進行比較。)

有幾種方法可以解決這個問題。 例如,可以為每個對象生成像ParentClass1:ChildClass2:ChildClass1:這樣的字符串,並將它們用作您將遍歷的TreeMapTrie的鍵。

不過,這是一個更簡單的解決方案。 以下類包含從類到實現它的所有對象的映射。 唯一的技巧是將對象添加到它所屬的所有存儲桶:

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]

Mifeet似乎已經完全回答了你的問題,但我懷疑你不應該嘗試做你提議的事情。 為什么不只是擁有可能發生碰撞的所有對象的主列表,然后根據需要使用instanceof過濾它?

這在概念上比你提議的要容易得多, 效率影響可能並不大。 (一般來說,你可能會聽到或聽過咒語:不要試圖過早地進行優化。)

說實話,我不確定你是否意識到對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;        
   }     
}

如果要將對象存儲在List<Object> ,請在每個元素上調用Class#isInstance() ,如果isInstance()返回true則將它們添加到另一個List

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

如果您只想要碰撞檢測,那么我會將它們添加到祖先類中的靜態集合中。 這將是最有效的解決方案。

如果你想要一個類的所有后代,你應該檢查反射API。 是的,據說它們很慢,但我懷疑它對於每幀都沒有計算的東西是否足夠重要。 而且對於每個幀中需要的東西,樹遍歷都會效率低下。 (@ Miffet關於字符串比較的建議可能比常規反射更慢。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM