2014-11-04 61 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

保持一个类名来实例映射表,确定类型插入到相应的列表实例: