带有容器对象键的Java Map,按容器对象字段值查找?

时间:2013-11-18 21:50:54

标签: java map key multikey

假设我有一个简单的Java对象,我们称之为DefinedData。它将包含许多不同类型的最终字段,例如字符串,整数,枚举,甚至可能是一组或两个字符串。总而言之,它只是一个相对简单的数据容器。这些中可能存在1k到2k,所有静态最终对象。大多数这些字段都是唯一的,因为没有其他DefinedData对象具有该字段的相同值。

这些将放入(DefinedData,Object)的Map中。现在,如果你有DefinedData对象,你可以轻松地从地图中获取该对象,但是如果你只有一个唯一的字段值呢?你不能把它传递给地图。您必须迭代键并检查,这将意味着使用查找方法为DefinedData中的每个字段包装地图。可行,但不是最漂亮的东西,特别是如果地图中有很多值和很多查找,这是可能的。无论是那个还是需要查找DefinedData对象,这将再次成为一堆地图......

这几乎听起来像是数据库的工作(基于任何列查找),但这不是解决这个特定问题的好方法。我还宁愿避免使用十几个不同的地图,每个地图都将一个字段从DefinedData映射到Object。我见过的多键映射不适用,因为它们需要所有键值,而不仅仅是一个。是否有可以处理此特定问题的Map,Collections或其他实现?

2 个答案:

答案 0 :(得分:0)

避免使用多个映射的唯一方法是以某种方式迭代所有DefinedData对象。原因是,你无法知道如何将它们分开或排序,直到提出请求为止。

如果你有一桶苹果,可以举一个例子。在任何时候,有人可能会出现并要求某种颜色,某种颜色或某种尺寸。您必须选择按其中一个类别进行排序,并且必须通过所有苹果搜索其他类别。 如果只有你可以有三套相同的苹果;每个类别一个。

拥有多个地图将是一个更快的解决方案,虽然占用更多的内存,而迭代将更容易实现,更慢,并使用更少的内存。

答案 1 :(得分:0)

我毫不犹豫地建议这一点,但您可以将查找封装在某种Indexer类后面,该类通过使用提供的对象字段的反射自动生成单个地图。

通过单一映射,我的意思是整个索引器只有一个映射,它根据字段名称和数据创建一个键(比如将表示字段名称的字符串与数据的字符串表示形式连接起来)。

针对索引器的查找将提供字段名称和数据值,然后在索引器封装的单个映射中查找。

我认为这不一定比类似的解决方案有任何优势,因为索引器由地图映射支持(字段名称映射到数据映射到对象)。

索引器也可以设计为使用注释,以便不是所有字段都被索引,只有那些被适当注释(反之亦然,带注释以排除字段)。

总的来说,地图解决方案的地图让我感觉更轻松,因为它削减了复杂键组装的步骤(对于某些字段数据类型可能会很复杂)。在任何一种情况下,将其全部封装在自动生成其地图的Indexer中似乎是可行的方法。

<强>更新

Indexer类型类创建了一个快速的非泛化概念证明(使用map map方法)。 这绝不是完成的工作,但说明了上述概念。一个主要的缺点是依赖bean,因此没有访问器方法的公共和私有字段对于这个索引器是不可见的。

public class Indexer
{
    private Map<String,Map<Object,Set<Object>>> index = new HashMap<String,Map<Object,Set<Object>>>();

    // Add an object to the index, all properties are indexed.
    public void add(Object object) throws Exception
    {
        BeanInfo info = Introspector.getBeanInfo(object.getClass());

        PropertyDescriptor[] propertyDescriptors = info.getPropertyDescriptors();
        for (PropertyDescriptor descriptor : propertyDescriptors)
        {
            String fieldName = descriptor.getName();
            Map<Object,Set<Object>> map = index.get(fieldName);
            if (map == null)
            {
                map = new HashMap<Object,Set<Object>>();
                index.put(fieldName, map);
            }
            Method method = descriptor.getReadMethod();
            Object data = method.invoke(object);
            Set<Object> set = map.get(data);
            if (set == null)
            {
                set = new HashSet<Object>();
                map.put(data, set);
            }
            set.add(object);
        }

    }

    // Retrieve the set of all objects from the index whose property matches the supplied.
    public Set<Object> get(String fieldName, Object value)
    {
        Map<Object,Set<Object>> map = index.get(fieldName);
        if (map != null)
        {
            Set<Object> set = map.get(value);
            if (set != null)
            {
                return Collections.unmodifiableSet(set);
            }
        }

        return null;
    }
}