Java 中的 Treemap 热图方法

Treemap's headmap method in Java

我正在检查 TreeMap 的 headMap 方法,其中 returns Map 的一部分,其键严格小于 toKey。所以我期望输出是 B、C,但它 returns 只有 B。这是我做的一件奇怪的事情,我像这样 return this.priority > o.priority ? 1 : -1; 更改了 compareTo 方法,然后它开始返回 C、B,这正是我所期待的.我确定这是不正确的,但是我怎样才能同时获得优先级低于 A 的 B、C。我在哪里弄错了。谢谢

NavigableMap<PolicyTypePriorityWrapper, String> treeMap = new TreeMap();
PolicyTypePriorityWrapper a = new PolicyTypePriorityWrapper("A", 2);
PolicyTypePriorityWrapper b = new PolicyTypePriorityWrapper("B", 1);
PolicyTypePriorityWrapper c = new PolicyTypePriorityWrapper("C", 1);

treeMap.put(a, "A");
treeMap.put(b, "B");
treeMap.put(c, "C");

NavigableMap<PolicyTypePriorityWrapper, String> map = treeMap.headMap(a, false);
Set<PolicyTypePriorityWrapper> policyTypePriorityWrappers = map.keySet();

for (PolicyTypePriorityWrapper pol: policyTypePriorityWrappers) {
    System.out.println(pol.getPolicyType());
}

PolicyTypePriorityWrapper.java

class PolicyTypePriorityWrapper implements Comparable<PolicyTypePriorityWrapper> {

    private String policyType;
    private int priority;

    public PolicyTypePriorityWrapper(final String policyType, final int priority) {
        this.policyType = policyType;
        this.priority = priority;
    }

    public String getPolicyType() {
        return this.policyType;
    }

    public int getPriority() {
        return this.priority;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        PolicyTypePriorityWrapper that = (PolicyTypePriorityWrapper) o;

        if (priority != that.priority) return false;
        return policyType.equals(that.policyType);
    }

    @Override
    public int hashCode() {
        int result = policyType.hashCode();
        result = 31 * result + priority;
        return result;
    }

    @Override
    public int compareTo(final PolicyTypePriorityWrapper o) {
        return Integer.compare(this.priority, o.priority);
    }
}

那是因为您没有遵循 JDK 文档指南,来自 Comprarable:

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

如您所见,您遇到了 a.compareTo(b) == 0!a.equals(b) 的情况。对于 TreeMap:

"B", 1"C", 1 都被认为是相等的

Note that the ordering maintained by a tree map, like any sorted map, and whether or not an explicit comparator is provided, must be consistent with equals if this sorted map is to correctly implement the Map interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.

For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.

那么发生的事情是你 compareTo 无法区分具有相同优先级但类型不同的两个元素,但是由于 TreeMap 使用 ONLY 该方法来确定两个元素是否相等,那么您不会首先将它们都添加到地图中。

如果treeMap.size() == 3你试过了吗?我的猜测是它首先是 2。

new PolicyTypePriorityWrapper("B", 1)不合格,因为它甚至没有进入treeMap

为什么?因为键是 PolicyTypePriorityWrapper 对象,根据它们的整数优先级值进行比较。由于bc具有相同的优先级,所以只有最后一个被保存到treeMap。比较abc的优先级低于a,等于b。键保留,值被替换。所以在地图中出现了一个条目 PolicyTypePriorityWrapper b 和新替换的值 C.

这是Map::put(K key, V value)方法的行为。

If the map previously contained a mapping for the key, the old value is replaced by the specified value.

现在 NavigableMap::headMap(K toKey, boolean inclusive) returns 此地图部分的视图,其键小于(或等于,如果 inclusive 为真)toKey(取自文档)。结果是显而易见的。只有 ab 留在 treeMap 中,所以 a 被过滤掉,因为它的优先级低于 b,只有 b 是有资格退货