[英]Unchecked cast from Object, generic class and wildcards
Here is my code: 这是我的代码:
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;
}
}
And compiler says: 编译器说:
Type safety: Unchecked cast from object to arraytasklist
类型安全:从对象到arraytasklist的未选中强制转换
I understand, that it's jst an warning, but if i try this code, there are no warnings: 我明白,这是一个警告,但如果我尝试这个代码,没有警告:
ArrayTaskList<?> other = (ArrayTaskList<?>) obj;
Is it more convenient solution? 这是更方便的解决方案吗?
The difference is that the raw type object is not typesafe while the unbounded wildcard gives you type safety. 区别在于原始类型对象不是类型安全的,而无界通配符为您提供类型安全性。
For example with a raw type you can have code like this: 例如,对于原始类型,您可以使用以下代码:
List list = new ArrayList<String>();
list.add(42); // integer
list.add(true); // boolean
list.add(whateverYouWant); // whatever you want
while this code: 而这段代码:
List<?> list2 = new ArrayList<String>();
list2.add(42);
list2.add(true);
will cause a compiler error. 将导致编译器错误。
When execution reaches that line, you know that obj
is an instance of ArrayTaskList
. 当执行到达该行时,您知道
obj
是ArrayTaskList
一个实例。 However, you don't know whether it is an ArrayTaskList<Integer>
or ArrayTaskList<String>
etc. 但是,您不知道它是
ArrayTaskList<Integer>
还是ArrayTaskList<String>
等。
Thus, the cast generates a warning (you could try to cast a ArrayTaskList<Integer>
to ArrayTaskList<String>
). 因此,
ArrayTaskList<Integer>
会生成警告(您可以尝试将ArrayTaskList<Integer>
ArrayTaskList<String>
为ArrayTaskList<String>
)。
However, you don't need the type information here, so using ArrayTaskList<?>
would indeed be the better solution here. 但是,这里不需要类型信息,因此使用
ArrayTaskList<?>
确实是更好的解决方案。
EDIT : 编辑 :
I had some misconception here, since even using type's boundary would cause the warning. 我在这里有一些误解,因为即使使用类型的边界也会引起警告。 As @svz pointed out,
ArrayTaskList<?>
won't add any assumptions and just enables type checking. 正如@svz所指出的,
ArrayTaskList<?>
不会添加任何假设,只会启用类型检查。
The compiler trusts you that the cast to ArrayTaskList
is ok, while the warning is generated because you make the assumption of obj
also having the type E
. 编译器信任您对
ArrayTaskList
是正确的,同时生成警告是因为您假设obj
也具有类型E
The compiler can't check that and thus issues the warning. 编译器无法检查,因此发出警告。 With
<?>
or <? extends XYZ>
用
<?>
或<? extends XYZ>
<? extends XYZ>
the compiler will ignore the type but will raise errors if any method that might fail is invoked. <? extends XYZ>
编译器将忽略该类型,但如果调用任何可能失败的方法,则会引发错误。
Consider the following example: 请考虑以下示例:
Your class is ArrayTaskList<E extends Number>
and thus you'd cast to ArrayTaskList<Number>
or ArrayTaskList<E>
(where E
could be Long
for example). 您的类是
ArrayTaskList<E extends Number>
,因此您将转换为ArrayTaskList<Number>
或ArrayTaskList<E>
(例如,其中E
可能为Long
)。
In that case the compiler doesn't know whether E
is of type Number
, Long
etc. and thus warns you, since obj
could be a ArrayTaskList<Double>
and casting that to ArrayTaskList<Number>
would allow you to add Longs to a list of Doubles (ouch). 在这种情况下,编译器不知道
E
是否为Number
, Long
等类型并因此警告您,因为obj
可能是ArrayTaskList<Double>
并且将其转换为ArrayTaskList<Number>
将允许您将Longs添加到列表中双打(哎哟)
Hence the compiler warns you of that cast. 因此编译器警告你那个演员。
Casting to ArrayTaskList<?>
would tell the compiler to ignore the type but raise errors if you called other.add(...)
, preventing you from accidential inconstencies. 转换为
ArrayTaskList<?>
会告诉编译器忽略该类型,但如果调用other.add(...)
引发错误,从而防止出现意外不一致的情况。
Edit 2: 编辑2:
I still have some misconception here (I'll think more about this), but so far, here's a way to cast without a warning and still use any upper bound that E
might provide: 我仍然有一些误解(我会更多地考虑这个),但到目前为止,这是一种没有警告的方法,仍然使用
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;
}
You could also pass in the ArrayTaskList
constructor an inscance of Class<E> clazz
and then the cast can be done clazz.cast(...)
: 您还可以在
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;
}
}
You could use the following implementation instead: 您可以使用以下实现:
@Override
public boolean equals(Object obj) {
return obj instanceof ArrayTaskList && obj.hashCode() == hashCode();
}
@Override
public int hashCode() {
return Arrays.hashCode(db);
}
That way, there's no unchecked cast problem anymore ;) 这样,就没有任何未经检查的演员问题;)
But please note that due to type erasure, 但请注意,由于类型擦除,
new ArrayTaskList<String>().equals(new ArrayTaskList<Integer>())
will return true
if both have the same db
array, even if one used String
while the other one Integer
as class parameter. 如果两者都具有相同的
db
数组,则返回true
,即使一个使用String
而另一个使用Integer
作为类参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.