简体   繁体   English

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

[英]How to determine current class type?

I had 2 classes, B and C , who needed to keep track of their instances, so each of them has an ArrayList of their respective types to which instances were added in the constructor. 我有两个类BC ,它们需要跟踪它们的实例,因此每个类都有一个各自类型的ArrayList ,这些实例在构造函数中添加了实例。

Since this seemed like common behaviour, I tried to find some sort of standard Java interface or class that expresses this behaviour, something like an InstanceManager interface. 由于这似乎是常见的行为,因此我尝试找到某种表达这种行为的标准Java接口或类,例如InstanceManager接口。 I didn't find any 我没找到

I ended up trying to write an abstract class for it and I got stuck because I don't know how to specify the specific type of the subclasses. 我最终尝试为其编写一个抽象类,但由于不知道如何指定子类的特定类型而陷入困境。 For example: 例如:

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

In this case, B.list or A.list would be lists of C objects, but I would actually want them to be lists of B and A objects, respectively. 在这种情况下, B.listA.list将是C对象的列表,但我实际上希望它们分别是BA对象的列表。
Is there any way I could make that happen easily? 有什么办法可以使我轻松实现这一目标?
I am thinking something along the lines of 我在想一些类似的事情

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

but that would obviously not work. 但这显然行不通。

I realise that I could probably use generics to handle this, but it feels redundant and I can't help wishing that there is a way to somehow infer the child class type in this situation. 我意识到我可能可以使用泛型来处理此问题,但是这感觉很多余,我不禁希望在这种情况下能够以某种方式推断子类的类型。

Also, is there any standard Java interface for handling instance management or unique instance id generation? 另外,是否有用于处理实例管理或唯一实例ID生成的标准Java接口?

EDIT: 编辑:
I have come to understand that static variables are not inherited, and the subclasses' static variables actually refer to the same thing. 我已经了解到静态变量不是继承的,并且子类的静态变量实际上是指同一件事。 As such, is there any way I can define instance managing behaviour without resorting to redundancy, having to write the same things in all subclasses? 这样,有什么方法可以定义实例管理行为而不必求助于冗余,而不必在所有子类中编写相同的内容?

Using generics, you can do something like: 使用泛型,您可以执行以下操作:

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

class A extends C<A> {
}

class B extends C<B> {
}

Keep a class name to list of instances mapping, determine the type at runtime to insert instances to the appropriate list: 保留类名以实例列表的映射关系,在运行时确定将实例插入适当列表的类型:

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

It's already been pointed out that a Map is appropriate here; 已经指出,在这里使用Map是合适的; however there are a few other concerns: 但是,还有其他一些问题:

  1. Multithreading. 多线程。
  2. Garbage collection. 垃圾收集。

#1 is fairly easy to factor in but worthwhile to point out. #1相当容易考虑,但值得指出。

#2 is important because you want to think carefully about whether or not keeping a list of all instances should prevent them from being garbage collected. #2很重要,因为您要仔细考虑是否保留所有实例的列表应防止它们被垃圾回收。 If not, you need to become familiar with the WeakReference class. 如果不是,则需要熟悉WeakReference类。

Here is an example of the more complicated case. 这是更复杂情况的示例。

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

As an example of usage, 作为用法的一个例子,

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

The output here is 这里的输出是

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

because this InstanceManager allows its referents to be garbage collected. 因为此InstanceManager允许其引用对象被垃圾收集。 If that's not the desired behavior (you aren't keeping references to the instances elsewhere) then of course you need to release them manually. 如果这不是所需的行为(您没有在其他位置保留对实例的引用),那么您当然需要手动释放它们。

But either way this allows you to do something like 但是,无论哪种方式,这都可以让您做类似的事情

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

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

where all instances of C and its subclasses are automatically managed and categorized by actual type. 其中C所有实例及其子类均按实际类型自动进行管理和分类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM