如何确定当前的班级类型?

时间:2014-11-04 16:57:08

标签: java class inheritance subclass instances

我有两个类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.list会是C个对象的列表,但实际上我希望它们是BA的列表对象分别 有什么办法可以轻易实现这一点吗?

我正在思考一些事情
public abstract class C { public static ArrayList<thisclass> list; }

但这显然不起作用。

我意识到我可能会使用泛型来处理这个问题,但感觉多余,我不禁希望在这种情况下有办法以某种方式推断子类类型。

此外,是否有用于处理实例管理或唯一实例ID生成的标准Java接口?

编辑:
我已经明白静态变量不是继承的,而子类的静态变量实际上指的是同一个东西。因此,有没有什么方法可以定义实例管理行为而不需要求助于冗余,必须在所有子类中编写相同的东西?

3 个答案:

答案 0 :(得分:0)

使用泛型,您可以执行以下操作:

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

class A extends C<A> {
}

class B extends C<B> {
}

答案 1 :(得分:0)

将类名保留到实例列表映射中,在运行时确定类型以将实例插入适当的列表:

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

答案 2 :(得分:0)

已经指出Map在这里是合适的;然而,还有一些其他问题:

  1. 多线程。
  2. 垃圾收集。
  3. #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及其子类的所有实例都是自动管理的,并按实际类型进行分类。