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