2015-10-01 52 views
2

我想为不同类的对象编程一种注册表。以类为关键的TreeMap

我有以下几点:

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

实现此接口的原型类将是以下几点:

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

我想建立这个界面的各种不同的实现。 我希望能够拥有一个Map对象,它可以从每个实现类映射到一个Map实例。

事情是这样的:

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

我知道我可以做这样的事情

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

但这种方式我会多写一些代码来确定名称,比较类等。有没有更简单的方法来实现这一点?

所以我想知道的是:是否有可能将类对象作为树形图中的键?

声明一个映射对象的语法是什么?映射从实现类C到映射对象从长对象(id)映射到C的实例?

我希望能够做的请求如下所示:

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

assuing ID以前那样

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

请告诉我,如果这还不清楚,我很难解释,因为英语不是我的母语。

预先感谢您。


编辑:

事实证明,我可以做一些非常接近我想要的东西,周围的地图定义泛型类时:

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

我用一个TreeMap的内部映射,因为我想轻松地返回按id排序的Class实例。

因此,精炼的问题是: 有没有办法做到这一点,没有类头的<T extends DbObject>子句?


编辑2:

通过它又在想,事实证明,约翰的回答是完全解决了这个。

这是我的最终代码:

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

它不需要在类头<T extends DbObject>条款。

回答

3

所以我想知道的是:是否有可能将类对象作为树图中的键?

TreeMap取决于是否有在键空间中的总顺序,由具有天然顺序(通过实施Comparable)键的类型所建立或者由单独的Comparator对象,您提供。 Class es没有自然顺序。可以想象,你可以写一个合适的Comparator,但是这对我来说似乎很有意思。

但是,为什么你特别需要一个TreeMap?您没有描述任何其他种类的Map都没有解决的要求。特别是,我几乎总是发现HashMap是一个更好的选择,我看不出有什么理由不适合这个。它当然可以有Class类型的对象作为键。此外,如果确实不需要任何特定的实施,那么您最好是宣称的类型只是简单的Map。这样,你可以实际上提供任何Map的实施,甚至改变你提供的一个,如果你发现这样做的理由。

什么将声明一个地图对象的语法中,从实现类C到地图的地图对象从长对象(ID)至C的实例每个映射?

您要求对每个值的类型的约束取决于相关键的类型,但是没有办法声明强制这种关系的类型。 Map是否适合某个特定的键或特定的值是单独映射的类型的函数,而不是其他类型的映射的函数。

您可以围绕访问您的地图编写泛型方法,它提供您所需的外观,但是需要投射数据检索方法。例如:

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

更新补充:

所以精致的问题是:有没有办法做到这一点,而不会在类头<T extends DbObject>条款?

是的,我已经写了。只要打一个简单的类声明就可以了。你不需要泛型类来拥有泛型方法。事实上,这两者是正交的。 常规泛型类的方法可以使用该类的类型参数。这并不能使它们成为通用的方法。如果方法声明自己的类型参数,则方法是通用的,正如我在上面所做的那样。你的get()方法也是这样做的,重要的是要明白,你在方法签名中明确声明的类型参数<T>会隐藏类的同名类型参数:它是不同的T

+0

这不是关于树图,我可以使用其他类型的地图,我知道。这是关于声明地图的语法。 –

+0

@StephanRichter,回答更新以解决您澄清的问题。 –

+0

好的,那基本上是我想知道的。我会让它开放一些日子,也许有人有一个更好的想法/解决方法/无论。如果没有,我会在接下来的日子里将你的答案标记为正确。谢谢,到目前为止。 –