簡體   English   中英

從Object,泛型類和通配符中取消選中

[英]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);

將導致編譯器錯誤。

當執行到達該行時,您知道objArrayTaskList一個實例。 但是,您不知道它是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是否為NumberLong等類型並因此警告您,因為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM