类魔法 - 自动按类型排序对象

时间:2011-02-16 17:29:01

标签: java generics

我想创建一种内存数据库,我可以在其中放置任何类型的对象EntityProxy。我想根据每个对象的类型和ID号(每个EntityProxy都有 - 为每个对象编制索引 - 就像为每种类型创建一个HashMap一样简单。

我可以用

之类的东西手动实现
public void put(Object o)
{
    if (o instanceof Car)
        carIndex.put(o.getId(), o);
    else if (o instanceof Bus)
        busIndex.put(o.getId(), o);

    ...
}

但我当然不想。我想要更像

的东西
public void <T extends EntityProxy> put(T o)
{
   indexMap.get(o.class).put(o.getId(), o);
}

我只是不放弃使用泛型词汇来做到这一点。我不知道问号在模板定义中意味着什么,真的 - 会像

HashMap<Class<?>, HashMap<Long, EntityProxy>> indexMap

工作?

4 个答案:

答案 0 :(得分:2)

那张地图还可以;如果你真的需要添加一点约束,那就试试吧:

Map<Class<? extends EntityProxy>, HashMap<Long, EntityProxy>> indexMap;

这将确保密钥类只能是EntityProxy.class或子类。

您可以将问号视为某些“任何东西”,但匿名。所以<?>表示真的是 - 任何Object<? extends EntityProxy>表示满足此条件的任何内容(通过“instanceof EntityProxy”测试)。< / p>

此处的类型安全性低于预期,因为您仍然可以将任何内容作为键和任何内容放在该映射中。我的意思是,你可以合法地把它放在地图上:

indexMap.put(EntityProxy1.class, new HashMap<Long, EntityProxy2>());

(假设EntityProxy1EntityProxy2都是EntityProxy的子类),因为密钥和值之间没有相关性。要强制执行此操作,需要按照以下方式声明映射的put()方法:

<T extends EntityProxy> put(Class<T> key, HashMap<Long, T> value);

T?非常相似,但主要区别在于它为您提供了一个可以在该上下文中引用它的名称。 所以,如果我说?代表“任何东西”,我会说T代表“某事”,因为一旦你宣布它就可以引用那些东西。

但是你需要一个自定义数据结构,因为java.util.Map不提供这种约束。如果您正在使用它,如代码示例中所示,我认为您确实不需要这些强制执行。

答案 1 :(得分:1)

请注意,在此示例中,我使用了List。您可以轻松地将此替换为您的Collection选择类并进行相应调整。

public interface Classifiable {
    String classification();
}

public abstract class Automobile implements Classifiable {
    // String classification defined in child classes
}

public class Car extends Automobile {
    public String classification() { return "Car"; }
}

public class Bus extends Automobile {
    public String classification() { return "Bus"; }
}

public class AutoMap {
    Map<String,List<Automobile>> theMap = new Map<String,List<Automobile>>();

    public AutoMap() { }

    public void add(Automobile a) {
        String type = a.classification();
        List<Automobile> list = theMap.get(type);
        if(list == null) {
            list = new LinkedList<Automobile>();
            theMap.put(type,list);
        }
        list.add(a);
    }

    public List<Automobile> getAutosOfType(String type){
        return theMap.get(type);
    }

}

public static void main(String[] args) {

    List<Automobile> autos = getRandomAutos(); // defined somewhere? :)
    AutoMap theAutomap = new AutoMap();
}

答案 2 :(得分:1)

如果你不介意使用类名,那就简单如下:

public void <T extends EntityProxy> put(T o)
{
    HashMap map = indexMap.get(o.getClass().getName());
    if (map == null) 
    {
        map = new HashMap();
        indexMap.put(o.getClass().getName(), map);
    }
    map.put(o.getId(), o);
}

此代码将在您继续创建所需的子哈希图。

如果您使用getClass().getName(),则会在com.mypackage.Bus表单上获取姓名。如果您愿意处理名称冲突并且只想要简单名称(在本例中为“Bus”),请改用getClass().getSimpleName()

答案 3 :(得分:1)

尝试:

Map<Class<?>, Map<Long, EntityProxy>> indexMap = new HashMap<Class<?>, Map<Long, EntityProxy>>();

public void put(EntityProxy entityProxy){ // generics don't add anything here
  ...

(我没有测试过)