的有界參數<T extends D<T>>
一個有效的替代品當然 - 這些「自我類型」通常用於限制亞型返回完全屬於自己的類型。考慮如下:
public interface Operation {
// This bit isn't very relevant
int operate(int a, int b);
}
public abstract class AbstractOperation<T extends AbstractOperation<T>> {
// Lets assume we might need to copy operations for some reason
public T copy() {
// Some clever logic that you don't want to copy and paste everywhere
}
}
酷 - 我們有一個父類,有一個有用的操作符,可以是特定於子類。例如,如果我們創建AddOperation
,它的通用參數是什麼?因爲「遞歸」通用的定義,這隻能是AddOperation給我們:
public class AddOperation extends AbstractOperation<AddOperation> {
// Methods etc.
}
,因此copy()
方法是保證返回AddOperation
。現在,讓我們來想象我們是愚蠢的,或惡意的,或創意,或什麼的,並試圖定義這個類:
public class SubtractOperation extends AbstractOperation<AddOperation> {
// Methods etc.
// Because of the generic parameters, copy() will return an AddOperation
}
這將由編譯,因爲泛型類型不在其範圍內被拒絕。這非常重要 - 這意味着在父類中,即使我們不知道具體類型是什麼(它甚至可能是編譯時不存在的類),copy()
方法將返回一個實例同一個子類。
如果簡單地用C<T extends C>
去,那麼SubtractOperation
這種怪異的定義將是合法的,而你失去了什麼T
在這種情況下,擔保 - 因此減法操作可以自身複製到添加操作。
這不是關於如何保護您的類層次結構免受惡意子類攻擊,更重要的是它能夠讓編譯器對涉及的類型提供更強的保證。如果你從其他職業altogther調用copy
任意Operation
,你的陣型之一保證結果將是同一類,而另一個將需要施放(和可能不是一個正確的演員,如同上面的SubtractOperation)。
事情是這樣的,例如:
// This prelude is just to show that you don't even need to know the specific
// subclass for the type-safety argument to be relevant
Set<? extends AbstractOperation> operations = ...;
for (AbstractOperation<?> op : operations) {
duplicate(op);
}
private <T extends AbstractOperation<T>> Collection<T> duplicate(T operation) {
T opCopy = operation.copy();
Collection<T> coll = new HashSet<T>();
coll.add(operation);
coll.add(opCopy);
// Yeah OK, it's ignored after this, but the point was about type-safety! :)
return coll;
}
上的duplicate
到T
不會是類型安全的與你提出的兩個邊界較弱第一線的分配,因此代碼不會編譯。 即使您明智地定義了所有的子類。
我知道這不是你問的問題,但第一個代碼段包含一個原始類型,這意味着它不是「正確」的通用代碼 - 應該用某些參數化「C」。這是我的觀點,如果不是爲了向後兼容,這將是一個硬編譯器錯誤。 –
我知道這不是(真的)你的問題,但是沒有**語義**區別,因爲程序在這兩種情況下的行爲方式都是相同的。 –