Map的Java泛型问题

时间:2011-09-23 16:58:43

标签: java generics

我有这个不应该编译的。

public boolean foo(final Map<String, String> map) {
     map.get(1);   // No error here?
}

3 个答案:

答案 0 :(得分:11)

get方法接受一个Object,因此1被自动装箱到一个Integer并且它编译得很好。尽管如此,你总是会回复null。

这样做是为了向后兼容。

// Ideal Map:
public V get(K key) {
 // impl here
}

// what we have
public V get(Object key) {
 // impl here
}

天蝎座的例子

import java.util.*;
class ScorpMain {

    /* This interface just has a single method on it returning an int */
    static interface SomeInterface {
        int foo();
    }

    /**
     * ExampleKey has an int and a string. It considers itself to be equal to
     * another object if that object implements SomeInterface and the two have
     * equal foo values. It believes this is sufficient, as its sole purpose is
     * to calculate this foo value.
     */
    static class ExampleKey implements SomeInterface {
        int i;
        String s;
        ExampleKey(int i, String s) { this.i = i; this.s = s; }
        public int foo() { return i * s.length(); }
        public int hashCode() { return i ^ s.hashCode(); }
        // notice - equals takes Object, not ExampleKey
        public boolean equals(Object o) {
            if(o instanceof SomeInterface) {
                SomeInterface so = (SomeInterface)o;
                System.out.println(so.foo() + " " + foo());
                return so.foo() == foo();
            }
            return false;
        }
    }

    /**
     * The ImposterKey stores it's foo and hash value. It has no calculation 
     * involved. Note that its only relation to ExampleKey is that they happen
     * to have SomeInterface.
     */
    static class ImposterKey implements SomeInterface {
        int foo;
        int hash;
        ImposterKey(int foo, int hash) { this.foo = foo; this.hash = hash; }
        public int foo() { return foo; }
        public boolean equals(Object o) {
                SomeInterface so = (SomeInterface)o;
                return so.foo() == foo();
        }
        public int hashCode() { return hash; }
    }

    /**
     * In our main method, we make a map. We put a key into the map. We get the
     * data from the map to prove we can get it out. Then we make an imposter, 
     * and get the data based on that. 
     * The moral of the story is, Map.get isn't sacred: if you can trick it 
     * into thinking that the object inside is equal to the object you give it 
     * in both equality and hash, it will give you the resulting object. It 
     * doesn't have anything to do with the type except that a given type is 
     * unlikely to be equal to another object that isn't of the given type.
     * This may seem like a contrived example, and it is, but it is something 
     * to be conscious of when dealing with maps. It's entirely possible you 
     * could get the same data and not realize what you're trying to do. Note 
     * you cannot ADD the imposter, because that IS checked at compile time.
     */
    public static void main(String[] args) {
        Map<ExampleKey,String> map = new HashMap<ExampleKey,String>();
        ExampleKey key = new ExampleKey(1337,"Hi");
        map.put(key,"Awesome!");
        String get = map.get(key);
        System.out.println(get); // we got awesome
        ImposterKey imposter = new ImposterKey(2674,3096); // make an imposter
        String fake = map.get(imposter);
        System.out.println(fake); // we got awesome again!
    }
}

答案 1 :(得分:3)

从Java 6开始,您编写的行完全等同于:

public boolean foo(final Map<String, String> map) {
    map.get(Integer.valueOf(1)); // compiles fine of course!
}

他们称之为“autoboxing”。另一方面是“autounboxing”,即:

public int bar(final Map<String, Integer> map) {
    return map.get("bar");
}

这一行相当于:

return map.get("bar").intValue();

当在地图中找不到请求的密钥时,有时会导致相当神秘的NullPointerException。对于刚接触这个概念的程序员来说,这是一个常见的陷阱。

希望有所帮助。

答案 2 :(得分:2)

  

我有这个不应该编译的。

为什么不呢?

.get()的定义表示它找到了键,使得给定的对象等于键。是的,在这种情况下我们知道对象是Integer,而Integer的{​​{1}}方法总是为.equals()对象返回false 。但一般来说,对于不同类的两个对象,我们不知道这一点。事实上,Java库中有些情况需要不同类的对象相等;例如,String要求列表相等,如果它们的内容相同且顺序相同,则不论类别如何。