2014-11-04 122 views
0

我有2個類,BC,他們需要跟蹤他們的實例,所以他們每個人都有一個ArrayList他們各自類型的實例添加到構造函數。如何確定當前類的類型?

由於這看起來很常見,我試圖找到某種標準的Java接口或類來表達這種行爲,如接口InstanceManager。我沒有找到任何

我最終試圖爲它寫一個抽象類,並且因爲我不知道如何指定子類的特定類型而卡住了。 例如:

public abstract class C { public static ArrayList<C> list; } 
public class A extends C { } 
public class B extends C { } 

在這種情況下,B.listA.listC對象的名單,但我真的希望他們能夠BA對象列表,分別。
有什麼辦法可以讓這種情況輕易發生?
我沿着

public abstract class C { public static ArrayList<thisclass> list; } 

行思考的東西,但會顯然是不行的。

我意識到我可以使用泛型來處理這個問題,但它感覺多餘,我不禁希望有一種方法可以在這種情況下以某種方式推斷子類的類型。

此外,是否有任何標準的Java接口來處理實例管理或唯一實例ID生成?

編輯:
我已經明白,靜態變量不是繼承的,子類的靜態變量實際上是指同一件事。因此,有什麼辦法可以定義實例管理行爲而不訴諸冗餘,必須在所有子類中寫入相同的東西?在運行時

abstract class C<T> { 
    public List<T> list; 
} 

class A extends C<A> { 
} 

class B extends C<B> { 
} 
+1

如果這是一個「靜態」持有者,那你的運氣不好。 'A'和'B'都將共享相同的列表。 – 2014-11-04 16:58:27

+0

爲什麼不使用Map >,根據我的運行時類型 – yurib 2014-11-04 16:59:51

+0

@yurib將每個實例插入到適當的列表中,但這意味着要有所有子類的集中式集合,並且我寧願擁有每種類型都有不同的列表。 – RedCat23 2014-11-04 17:05:39

回答

0

已經指出Map在這裏是合適的;然而還有一些其他問題:

  1. 多線程。
  2. 垃圾收集。

# 1是相當容易的因素,但值得指出的。

# 2很重要,因爲您要仔細考慮是否保留所有實例的列表應該防止它們被垃圾收集。如果不是,則需要熟悉WeakReference課程。

下面是一個更復雜情況的例子。

public final class InstanceManager<T> { 
    private final Map<Class<?>, List<Reference<T>>> refMap = (
     new HashMap<Class<?>, List<Reference<T>>>() 
    ); 

    public synchronized <U extends T> U manage(U instance) { 
     Class<?> cls = instance.getClass(); 
     List<Reference<T>> refList = refMap.get(cls); 

     if(refList == null) { 
      refList = new LinkedList<Reference<T>>(); 
      refMap.put(cls, refList); 
     } 

     refList.add(new WeakReference<T>(instance)); 
     return instance; 
    } 

    public synchronized <U extends T> List<U> getAll(Class<U> cls) { 
     List<U> returnList = new LinkedList<U>(); 

     List<Reference<T>> refList = refMap.get(cls); 
     if(refList != null) { 

      Iterator<Reference<T>> it = refList.iterator(); 
      while(it.hasNext()) { 
       T instance = it.next().get(); 

       if(instance == null) { 
        it.remove(); 
       } else { 
        returnList.add(cls.cast(instance)); 
       } 
      } 
     } 

     return returnList; 
    } 
} 

作爲使用的例子,

InstanceManager<Object> im = new InstanceManager<Object>(); 

Object o1 = im.manage(new Object()); 
Object o2 = im.manage(new Object()); 

String s1 = im.manage("a"); 
String s2 = im.manage(new String("b")); 

System.out.println("Object count: " + im.getAll(Object.class).size()); 
System.out.println("String count: " + im.getAll(String.class).size()); 

o2 = s1 = s2 = null; 

System.gc(); 
Thread.sleep(1000); 

System.out.println("Object count: " + im.getAll(Object.class).size()); 
System.out.println("String count: " + im.getAll(String.class).size()); 

輸出這裏是

 
Object count: 2 
String count: 2 
Object count: 1 
String count: 1 

因爲這InstanceManager允許其所指對象是垃圾收集。如果這不是所期望的行爲(您並未保持對其他地方的實例的引用),那麼當然您需要手動發佈它們。

但無論哪種方式,這允許你做這樣

public abstract class C { 
    private static final InstanceManager<C> manager = new InstanceManager<C>(); 

    protected C() { 
     manager.manage(this); 
    } 
} 

一些地方和它的子類的C所有實例自動管理和實際類型分類。

+0

明智的答案,謝謝。但是,如果我想讓'InstanceManager'不再是'final',將其方法設置爲'private'並繼承它,它會起作用嗎? – RedCat23 2014-11-04 19:30:17

+0

另外,你爲什麼把'HashMap'初始化放在了鬼臼中? – RedCat23 2014-11-04 19:31:07

+0

嘗試從實例管理器繼承聽起來像是一場設計噩夢。例如,最好使它成爲「C」的「公共靜態」成員。更好的分離問題。將新的HashMap加爲括號只是我使用的多行語法。除了它看起來不錯,對我來說沒有意義。 – Radiodef 2014-11-04 19:47:34

0

使用泛型,你可以這樣做

Map<String,List<?>> instances; 
.... 
instances.get(instance.getClass().getName()).add(instance); 
+0

但是這不會保存實例,因爲它不是靜態的。請仔細閱讀問題 – 2014-11-04 17:26:38

0

保持一個類名來實例映射表,確定類型插入到相應的列表實例: