这是我的代码:
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;
解决方案更方便吗?
答案 0 :(得分:3)
区别在于原始类型对象不是类型安全的,而无界通配符为您提供类型安全。
例如,对于原始类型,您可以使用以下代码:
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);
会导致编译错误。
答案 1 :(得分:0)
当执行到达该行时,您知道obj
是ArrayTaskList
的实例。
但是,您不知道它是ArrayTaskList<Integer>
还是ArrayTaskList<String>
等。
因此,演员阵容会产生警告(您可以尝试将ArrayTaskList<Integer>
投射到ArrayTaskList<String>
)。
但是,您不需要此处的类型信息,因此使用ArrayTaskList<?>
确实是更好的解决方案。
修改强>:
我在这里有一些误解,因为即使使用类型的边界也会引起警告。
正如@svz指出的那样,ArrayTaskList<?>
不会添加任何假设,只会启用类型检查。
编译器相信转换为ArrayTaskList
是正常的,而生成警告是因为您假设obj
也具有类型E
。编译器无法检查,因此发出警告。对于<?>
或<? extends XYZ>
,编译器将忽略该类型,但如果调用可能失败的任何方法,则会引发错误。
考虑以下示例:
您的课程为ArrayTaskList<E extends Number>
,因此您可以投放到ArrayTaskList<Number>
或ArrayTaskList<E>
(例如E
可能是Long
)。
在这种情况下,编译器不知道E
是Number
,Long
等类型,因此警告你,因为obj
可能是ArrayTaskList<Double>
1}}并将其转换为ArrayTaskList<Number>
将允许您将Longs添加到双打(ouch)列表中。
因此编译器会警告你那个演员。
转换为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;
}
答案 2 :(得分:0)
您还可以向ArrayTaskList
构造函数传递Class<E> clazz
的内容,然后可以完成演员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;
}
}
答案 3 :(得分:0)
您可以改用以下实现:
@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>())
如果两者都具有相同的true
数组,将返回db
,即使一个使用String
而另一个Integer
作为类参数。