我有这个不应该编译的。
public boolean foo(final Map<String, String> map) {
map.get(1); // No error here?
}
答案 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
要求列表相等,如果它们的内容相同且顺序相同,则不论类别如何。