为什么HashMap#containsKey采用Object类型的参数?

时间:2009-12-18 04:32:12

标签: java

一位同事遇到了一个错误,其中HashMap#containsKey用于验证键值对是否存在。指定的键是不同的类型,因此该方法始终返回false。例如(假设地图填充了他想要检索的对象):

Map<String, String> map = new HashMap<String, String>();
Long value = new Long(12);
boolean hasString = map.containsKey(value);

我的问题是:

为什么Map实现强制您放置K类型的键和V类型的值,但containsKey()方法允许您指定任何对象?

Map接口中还有其他方法,例如get()也接受Object类型的参数。

1 个答案:

答案 0 :(得分:2)

我认为这是因为Java的Map实现使用.equals()命令来确定两个对象是否相等,以用于.containsKey().remove()等方法。并且由于.equals()与一般对象进行比较(如果你覆盖它,你通常需要在顶部检查if (!(t instanceof T)) { return false; }但是没有实际规定A和B必须是同一类型A.equals(B)为真。

以下是一些突出差异的代码。可能没做你期望的事。

import java.util.*;

public class Test {

    static class Foo implements Comparable {
        public String a;

        public boolean equals(Object obj) {
            if (obj instanceof Bar) { return a.equals((((Bar) obj).b)); }
            return false;
        }

        public int compareTo(Object o) {
            return this.equals(o) ? 0 : -1;
        }
    }

    static class Bar implements Comparable {
        public String b;

        public boolean equals(Object obj) {
            if (obj instanceof Foo) { return b.equals((((Foo) obj).a)); }
            return false;
        }

        public int compareTo(Object o) {
            return this.equals(o) ? 0 : -1;
        }
    }   

    public static void main(String [] args) {
        Map<Foo, Bar> test = new TreeMap<Foo, Bar>();
        Foo foo = new Foo();
        Bar bar = new Bar();

        foo.a = "Hello";
        bar.b = "Hello";

        System.out.println(foo.equals(bar));
        System.out.println(bar.equals(foo));

        test.put(foo, bar);

        System.out.println(test.containsKey(bar));
        System.out.println(test.containsValue(foo));
    }

}