[英]Unchecked cast from Object, generic class and wildcards
这是我的代码:
public class ArrayTaskList<E> {
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ArrayTaskList<E> other = (ArrayTaskList<E>) obj;
if (!Arrays.equals(db, other.db))
return false;
return true;
}
}
编译器说:
类型安全:从对象到arraytasklist的未选中强制转换
我明白,这是一个警告,但如果我尝试这个代码,没有警告:
ArrayTaskList<?> other = (ArrayTaskList<?>) obj;
这是更方便的解决方案吗?
区别在于原始类型对象不是类型安全的,而无界通配符为您提供类型安全性。
例如,对于原始类型,您可以使用以下代码:
List list = new ArrayList<String>();
list.add(42); // integer
list.add(true); // boolean
list.add(whateverYouWant); // whatever you want
而这段代码:
List<?> list2 = new ArrayList<String>();
list2.add(42);
list2.add(true);
将导致编译器错误。
当执行到达该行时,您知道obj
是ArrayTaskList
一个实例。 但是,您不知道它是ArrayTaskList<Integer>
还是ArrayTaskList<String>
等。
因此, ArrayTaskList<Integer>
会生成警告(您可以尝试将ArrayTaskList<Integer>
ArrayTaskList<String>
为ArrayTaskList<String>
)。
但是,这里不需要类型信息,因此使用ArrayTaskList<?>
确实是更好的解决方案。
编辑 :
我在这里有一些误解,因为即使使用类型的边界也会引起警告。 正如@svz所指出的, ArrayTaskList<?>
不会添加任何假设,只会启用类型检查。
编译器信任您对ArrayTaskList
是正确的,同时生成警告是因为您假设obj
也具有类型E
编译器无法检查,因此发出警告。 用<?>
或<? extends XYZ>
<? extends XYZ>
编译器将忽略该类型,但如果调用任何可能失败的方法,则会引发错误。
请考虑以下示例:
您的类是ArrayTaskList<E extends Number>
,因此您将转换为ArrayTaskList<Number>
或ArrayTaskList<E>
(例如,其中E
可能为Long
)。
在这种情况下,编译器不知道E
是否为Number
, Long
等类型并因此警告您,因为obj
可能是ArrayTaskList<Double>
并且将其转换为ArrayTaskList<Number>
将允许您将Longs添加到列表中双打(哎哟)
因此编译器警告你那个演员。
转换为ArrayTaskList<?>
会告诉编译器忽略该类型,但如果调用other.add(...)
引发错误,从而防止出现意外不一致的情况。
编辑2:
我仍然有一些误解(我会更多地考虑这个),但到目前为止,这是一种没有警告的方法,仍然使用E
可能提供的任何上限:
public boolean equals(Object obj) {
...
return equals_((ArrayTaskList<?>)obj);
}
protected boolean equals_(ArrayTaskList<? extends Number> other)
{
if (!Arrays.equals(db, other.db))
return false;
return true;
}
您还可以在ArrayTaskList
构造函数中传入Class<E> clazz
的inscance,然后可以使用clazz.cast(...)
进行clazz.cast(...)
:
public class ArrayTaskList<E> {
Class<ArrayTaskList<E>> clazz;
public ArrayTaskList(Class<ArrayTaskList<E>> c) {
clazz = c;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ArrayTaskList<E> other = clazz.cast(obj);
if (!Arrays.equals(db, other.db))
return false;
return true;
}
}
您可以使用以下实现:
@Override
public boolean equals(Object obj) {
return obj instanceof ArrayTaskList && obj.hashCode() == hashCode();
}
@Override
public int hashCode() {
return Arrays.hashCode(db);
}
这样,就没有任何未经检查的演员问题;)
但请注意,由于类型擦除,
new ArrayTaskList<String>().equals(new ArrayTaskList<Integer>())
如果两者都具有相同的db
数组,则返回true
,即使一个使用String
而另一个使用Integer
作为类参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.