2

这是我的代码:

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;

是不是更方便的解决方案?

4

4 回答 4

4

不同之处在于原始类型对象不是类型安全的,而无界通配符为您提供类型安全。

例如,对于原始类型,您可以使用如下代码:

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);

将导致编译器错误。

于 2013-10-01T15:26:33.403 回答
0

您还可以在ArrayTaskList构造函数中传递一个 inscance ,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;
    }
}
于 2013-10-01T15:27:23.413 回答
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作为类参数。

于 2013-10-01T15:29:19.453 回答
0

当执行到达该行时,您知道这objArrayTaskList. 但是,您不知道它是一个ArrayTaskList<Integer>还是ArrayTaskList<String>等。

因此,强制转换会生成警告(您可以尝试将 a 强制转换ArrayTaskList<Integer>ArrayTaskList<String>)。

但是,您不需要此处的类型信息,因此在这里使用ArrayTaskList<?>确实是更好的解决方案。

编辑

我在这里有一些误解,因为即使使用类型的边界也会导致警告。正如@svz 指出的那样,ArrayTaskList<?>不会添加任何假设,只会启用类型检查。

编译器相信您可以转换ArrayTaskList为,而生成警告是因为您假设obj也具有 type E。编译器无法检查,因此发出警告。With <?>or<? extends XYZ>编译器将忽略该类型,但如果调用任何可能失败的方法将引发错误。

考虑以下示例:

你的班级是ArrayTaskList<E extends Number>,因此你会投到ArrayTaskList<Number>or ArrayTaskList<E>(例如E可能在哪里)。Long

在这种情况下,编译器不知道 is 是否E属于 typeNumberLong,因此会警告您,因为obj可能是 aArrayTaskList<Double>并将其转换为ArrayTaskList<Number>允许您将 Longs 添加到 Doubles 列表中(哎哟)。

因此,编译器会警告您该演员表。

强制转换 toArrayTaskList<?>会告诉编译器忽略类型,但如果您调用 会引发错误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;
}
于 2013-10-01T15:18:35.117 回答