[英]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.