简体   繁体   English

以类为键的TreeMap

[英]TreeMap with Classes as Key

I am trying to program a kind of registry for objects of different classes. 我正在尝试为不同类的对象编写一种注册表。

I have the following: 我有以下几点:

public interface DbObject{
    void setId(long id);
    Long getId();
}

A prototypic class implementing this interface would be the following: 实现此接口的原型类如下:

public class BasicDbObject implements DbObject{
    private long id=null;
    void setId(long id){
        this.id=id;
    }
    Long getId(){
        return id;
    }
}

I want to build various different Implementations of this Interface. 我想构建此接口的各种不同实现。 And I want to be able to have a Map object, that maps from each implementing class to a Map of instances. 而且我希望能够有一个Map对象,该对象从每个实现类映射到实例Map。

Something like this: 像这样:

Map <Class<C implements DbObject> , Map<Long, C>> registry = new TreeMap/HashMap/SomeOtherKindOfMap (...)

I know I could do something like 我知道我可以做类似的事情

Map <String,Map<Long,DbObjects>> registry = new ...

But this way I would have to write some more code for determining names, comparing classes and so on. 但是这样,我将不得不编写更多代码来确定名称,比较类等。 Is there an easier way to accomplish this? 有没有更简单的方法可以做到这一点?

So what I want to know: is it possible to have class objects as keys in a tree map? 所以我想知道:树形图中是否可以将类对象作为键?

What would be the syntax to declare a map object, that maps from implementing classes C to a map objects each mapping from a long object (the id) to instances of C? 声明一个映射对象的语法是什么,该对象从实现类C映射到一个映射对象,每个映射对象都从一个长对象(id)映射到C的实例?

I want to be able to do requests like the following: 我希望能够发出如下请求:

BasicObject bo = registry.get(BasicObject.class).get(42);

assuing id did 确认身份证确实

BasicObject bo=new BasicObject(...);
innerMap = new SomeMap<Long,BasicObject>();
innerMap.put(42,bo);
registry.put(BasicObject.class,innerMap);

before. 之前。

Please tell me, if this still is not clear, I have difficulties to explain, since english is not my mother tongue. 请告诉我,如果仍然不清楚,我将很难解释,因为英语不是我的母语。

Thank you in advance. 先感谢您。


Edit: 编辑:

It turns out, i can do something very close to what I want, when defining a generic class around the map: 事实证明,在地图上定义通用类时,我可以做一些非常接近我想要的事情:

public class ObjectRegistry <T extends DbObject>{

    private HashMap<Class<T>, TreeMap<Long,T>> registry=null;

    ObjectRegistry(){
        registry=new HashMap<Class<T>, TreeMap<Long,T>>();
    }
    public void register(T dbObject){
        TreeMap<Long, T> map = registry.get(dbObject.getClass());
        if (map==null){
            map=new TreeMap<Long,T>();
            registry.put((Class<T>) dbObject.getClass(),map);
        }
        map.put(dbObject.getId(),dbObject);
    }

    public <T extends DbObject>T get(Class<T> objectClass,long id){
        TreeMap<Long, T> map = (TreeMap<Long, T>) registry.get(objectClass);
        if (map != null){
            return map.get(id);
        }
        return null;
    }

    public TreeMap<Long,T> getAll(Class<T> dbObjectClass) {
        return registry.get(dbObjectClass);
    }
}

I use a TreeMap for the inner mappings since I want to easily return Class instances sorted by id. 我使用TreeMap作为内部映射,因为我想轻松返回按ID排序的Class实例。

So the refined question is: Is there a way to do this, without the <T extends DbObject> clause in the Class head? 因此,改进后的问题是:有没有办法在Class头中没有<T extends DbObject>子句呢?


Edit 2: 编辑2:

Thinking through it again, it turns out that John's answer is exactly the solution to this. 再次思考,事实证明约翰的答案正是解决这个问题的方法。

Here is my final code: 这是我的最终代码:

HashMap<Class<? extends DbObject>, TreeMap<Long, ? extends DbObject>> registry = null;

public <T extends DbObject> T get(Class<T> clazz, long id) {
    TreeMap<Long, T> map = (TreeMap<Long, T>) registry.get(clazz);
    if (map != null) {
        return map.get(id);
    }
    return null;
}

public <T extends DbObject> void register(T dbObject) {
    TreeMap<Long, T> map = (TreeMap<Long, T>) registry.get(dbObject.getClass());
    if (map == null) {
        map = new TreeMap<Long, T>();
        registry.put((Class<T>) dbObject.getClass(), map);
    }
    map.put(dbObject.getId(), dbObject);
}


public <T extends DbObject> TreeMap<Long, T> getAll(Class<T> dbObjectClass) {
    return (TreeMap<Long, T>) registry.get(dbObjectClass);
}

It does not need the <T extends DbObject> clause in the Class head. 它不需要Class头中的<T extends DbObject>子句。

So what I want to know: is it possible to have class objects as keys in a tree map? 所以我想知道:树形图中是否可以将类对象作为键?

TreeMap depends on there being a total order over the key space, as established by the key type having a natural order (by implementing Comparable ) or by a separate Comparator object that you provide. TreeMap取决于键空间上的总顺序,该顺序由具有自然顺序的键类型(通过实现Comparable )或由您提供的单独的Comparator对象确定。 Class es do not have a natural order. es Class没有自然顺序。 It is conceivable that you could write a suitable Comparator , but that seems very contrived to me. 可以想象您可以编写一个合适的Comparator ,但这对我来说似乎很虚构。

But why do you specifically need a TreeMap ? 但是,为什么您特别需要TreeMap You didn't describe any requirement that would not be at least as well addressed by any other kind of Map . 您没有描述任何其他Map无法解决的要求。 In particular, I almost always find HashMap to be a better choice, and I don't see any reason why it would be unsuitable in this one. 特别是,我几乎总是觉得HashMap是更好的选择,而且我看不出有什么理由不适合使用HashMap It can certainly have objects of type Class as keys. 它当然可以将Class类型的对象作为键。

Moreover, if indeed you don't need any particular implementation, then you are best off declaring the type simply as a Map . 而且,如果确实不需要任何特定的实现,那么最好将类型简单地声明Map That way you can actually provide any Map implementation, and even change which one you do provide if you ever discover a reason to do so. 这样,您实际上可以提供任何Map实现,甚至在发现原因的情况下甚至可以更改您提供的实现。

What would be the syntax to declare a map object, that maps from implementing classes C to a map objects each mapping from a long object (the id) to instances of C? 声明一个映射对象的语法是什么,该对象从实现类C映射到一个映射对象,每个映射对象都从一个长对象(id)映射到C的实例?

You ask that the constraints on the type of each value be dependent on the type of the associated key, but there is no way to declare a type that enforces such a relationship. 您要求对每个值的类型的约束取决于关联键的类型,但是无法声明强制这种关系的类型。 Whether a particular key or a particular value is appropriate for the Map is a function of the type of the map alone, not of each others' type. 特定的键或特定的值是否适合于Map ,这仅取决于map的类型,而不取决于彼此的类型。

You can write generic methods around access to your map that provide the appearance of what you want, but the data retrieval methods will need to cast. 您可以在访问地图的周围编写通用方法,以提供所需外观,但是将需要强制转换数据检索方法。 For example: 例如:

Map<Class<? extends DbObject>, Map<Long, ? extends DbObject>> registry = /*...*/;

<T extends DbObject> Map<Long, T> getRegistryMap(Class<T> clazz) {
    return (Map<Long, T>) registry.get(clazz);
}

<T extends DbObject> T get(Class<T> clazz, Long id) {
    Map<Long, T> map = getRegistryMap(clazz);

    return (map == null) ? null : map.get(id);
}

<T extends DbObject> T put(Class<T> clazz, Long id, T obj) {
    Map<Long, T> map = getRegistryMap(clazz);

    if (map == null) {
        map = new HashMap<>();
        registry.put(clazz, map);
    }
    return map.put(id, obj);
}

Updated to add: 更新后添加:

So the refined question is: Is there a way to do this, without the <T extends DbObject> clause in the Class head? 因此,改进后的问题是:有没有办法在Class头中没有<T extends DbObject>子句呢?

Yes, what I already wrote. 是的,我已经写过了。 Just slap a plain class declaration around it. 只需在其周围拍一个普通的类声明即可。 You do not need a generic class to have generic methods. 您不需要泛型类即可具有泛型方法。 In fact, the two are orthogonal. 实际上,两者是正交的。 Regular methods of a generic class can use that class's type parameters. 泛型类的常规方法可以使用该类的类型参数。 That does not make them generic methods. 但这并不使它们成为通用方法。 A method is generic if it declares its own type parameter(s), as mine above do. 如果方法声明自己的类型参数,则该方法是通用的,就像上面的方法一样。 Your get() method also does that, and it is important to understand that the type parameter <T> you declare explicitly in the method signature shadows the class's type parameter of the same name: it is a different T . 您的get()方法也可以做到这一点,重要的是要了解,您在方法签名中显式声明的类型参数<T>遮盖了同名类的类型参数:它是一个不同的T

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

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