[英]Is it possible to avoid unchecked casting when calling `clone()`?
這是一個人為的例子來說明這個問題。 我知道有一些方法不會產生編譯器警告,您也可以禁用警告。 我想知道如果沒有任何這些技巧,這是否可能。
鑒於此代碼:
1 public static void main(String[] args) {
2 Map<String,String> map = null;
3
4 HashMap<String,String> hmap;
5
6 if(map instanceof HashMap)
7 hmap = (HashMap<String,String>)map;
8 else
9 hmap = new HashMap<String,String>(map);
10
11 map = (Map<String,String>)hmap.clone();
12
13 Object o = hmap.clone();
14 if(o instanceof Map<?,?>)
15 map = (Map<String,String>)o;
16 }
第 11 行和第 15 行的代碼都會生成編譯器警告:
Unchecked cast from Object to Map<String,String>
第 11 行有點可以理解: Object.clone()
返回Object
,並且在轉換之前沒有進行instanceof
檢查。 程序員知道克隆將是Map<String,String>
,但編譯器無法證明這一點。
不過,第 15 行讓我感到困惑。 通常,使用instanceof
檢查變量的類型然后立即轉換它不會產生這樣的警告。 事實上,用這樣的非參數化類替換代碼將不會在以下任何代碼行中產生警告:
static class A {}
static class B extends A implements Cloneable {
public Object clone() { return null; }
}
public static void main(String[] args) {
A a = null;
B b;
if(a instanceof B)
b = (B)a;
else
b = new B();
a = (A)b.clone();
Object o = b.clone();
if(o instanceof A)
a = (A)o;
}
回到原始代碼(使用Map<String,String>
引用),即使在代碼末尾添加這個笨拙的結構也會產生類似的警告:
map = (Map<String,String>)hmap.getClass().cast(o);
這次的警告是Unchecked cast from capture#11-of? extends HashMap to Map<String,String>
Unchecked cast from capture#11-of? extends HashMap to Map<String,String>
。 試圖寫:
map = HashMap<String,String>.class.cast(o);
Generates a compiler error because it can't figure out that HashMap<String,String>.class
is a static class reference in the same way that eg HashMap.class
, so we have to use a reference of the "correct" type to call Class.cast
。
這是 Java 做不到的嗎?
這是 Java 做不到的嗎?
是的,它就是這樣設計的。
看HashMap克隆方法的java源碼(1.8):
@SuppressWarnings("unchecked")
@Override
public Object clone() {
HashMap<K,V> result;
try {
result = (HashMap<K,V>)super.clone();
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
result.reinitialize();
result.putMapEntries(this, false);
return result;
}
它使用@SuppressWarnings("unchecked")
來抑制super.clone()
上的警告。
你不能完全避免它,但如果你的代碼有很多 clone() 方法,你可以通過提取到方法來最小化這些警告:
@SuppressWarnings("unchecked")
HashMap<String,String> cloneWithoutWarning(HashMap<String,String> map) { return (HashMap<String,String>) map.clone(); }
通常,使用 instanceof 檢查變量的類型然后立即轉換它不會產生這樣的警告。
這不是真的。 instanceof
對強制轉換警告沒有影響。
這不是關於此演員陣容中可能出現的ClassCastException
的警告。 未經檢查的演員表意味着 Java 無法安全地進行演員表。 這意味着 cast 可能會在沒有ClassCastException
的情況下通過,但類型不匹配。 這可能會導致來自意外地方的ClassCastException
。
在這種情況下,這是一個真正的問題。 HashMap.clone()
返回Object
以實現向后兼容性。 沒有辦法判斷它的實現是否是類型安全的。 例如:
import java.util.*;
class Main {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap() {
@Override
public Object clone() {
HashMap o = (HashMap)super.clone();
o.put("x", new Object());
return o;
}
};
Map<String,String> copy = (Map<String,String>)map.clone(); // will pass
System.out.println(copy.get("x")); // no cast but fails with ClassCastException
}
}
clone()
是有問題的。 如果可能,只需創建一個新的HashMap
。
如果您必須使用克隆,請僅使用安全強制轉換:
Map<?, ?> copy = (Map<?, ?>)map.clone();
System.out.println((String)copy.get("x")); // explicit cast will fail
除非您正在處理遺留代碼(非通用),否則應將未經檢查的強制轉換視為 hacks/workarounds。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.