[英]Java generics problem with Map
我有這個不應該編譯。
public boolean foo(final Map<String, String> map) {
map.get(1); // No error here?
}
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!
}
}
從Java 6開始,您編寫的行完全等同於:
public boolean foo(final Map<String, String> map) {
map.get(Integer.valueOf(1)); // compiles fine of course!
}
他們稱之為“自動裝箱”。 另一方面是“autounboxing”,即:
public int bar(final Map<String, Integer> map) {
return map.get("bar");
}
這一行相當於:
return map.get("bar").intValue();
當在地圖中找不到請求的密鑰時,有時會導致相當神秘的NullPointerException。 對於剛接觸這個概念的程序員來說,這是一個常見的陷阱。
希望有所幫助。
我有這個不應該編譯。
為什么不?
.get()
的定義表示它找到了鍵,使得給定的對象等於鍵。 是的, 在這種情況下,我們知道對象是一個Integer
,而Integer
的.equals()
方法總是為String
對象返回false。 但一般來說,對於不同類的兩個對象,我們不知道這一點。 事實上,Java庫中有些情況需要不同類的對象相等; 例如,如果列表的內容相同且順序相同,則java.util.List
要求列表相等,而不管類是什么。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.