[英]Java Generics, how to enforce two arguments of a method that extend a superclass to have a same type?
假設我有一個類層次結構如下:
class Vehicle;
class Car extends Vehicle;
class Plane extends Vehicle;
我有一個比較兩個對象的函數
public <T extends Vehicle> generateDiff(T original, T copy)
在編譯時,上面的方法保證兩個對象是Vehicle
,但是它不能確保兩個對象的類型是相同的。
generateDiff(new Car(), new Car()); //OK
generateDiff(new Plane(), new Plane()); //OK
generateDiff(new Car(), new Plane()); //WRONG
我可以在編譯時使用泛型來實現這個目的嗎?
Ps:目前,我已實現它將拋出異常,如果兩個對象的Class
不相同。 但我對此並不滿意。
提前致謝。
是的,你可以(有點)!
類型T
是從參數推斷出來的,但您可以指定類型:
MyClass.<Car>generateDiff(new Car(), new Plane()); // generates a compile error
如果沒有鍵入方法,類型T
被推斷為滿足使用邊界的最窄類,因此對於參數Car
和Plane
,最有效的類型是Vehicle
,因此這兩行是等效的:
generateDiff(new Car(), new Plane()); // type is inferred as Vehicle
MyClass.<Vehicle>generateDiff(new Car(), new Plane());
上面的代碼假設generateDiff()
是一個靜態方法。 如果它是一個實例方法,您可以鍵入您的類並在您的方法中使用該類型。
一旦深入了解它,就會有點抽象。 您還必須為該函數提供類類型(見下文)。 如果您想強制執行此類行為,我建議您編寫單獨的方法來接受您希望比較的類型。 無論如何:
public <C extends Vehicle> void generateDiff(Class<C> type, C original, C copy);
你可以這樣使用它:
generateDiff(Plane.class, new Plane(), new Plane()); // OK
generateDiff(Car.class, new Car(), new Car()); // OK
generateDiff(Plane.class, new Plane(), new Car()); // ERROR
generateDiff(Vehicle.class, new Plane(), new Car()); // OK
不知道為什么任何理智的人會想要這樣做! :)
在我看來,任何能夠接受車輛作為參數的方法都不可能接受CAR和PLANE。 由於編譯器不知道將會出現什么類型的對象(可以是CAR,BUS,PLANE),因此不能保證兩個參數類型完全相同。 如果有人擴展CAR並創建一個FORD? 兩個對象都是CAR類型。
只有這樣才能確保在運行時使用自定義邏輯。
嚴格地說,你的問題的答案是“不,這是不可能的”。
但是,有一種解決方法 。 創建方法<T extends Vehicle> VehicleDiffer<T> compare(T vehicleA)
其中VehicleDiffer<T>
的方法ReturnType with(T vehicleB)
。 現在您可以進行以下調用:
compare(new Car()).with(new Car()); // okay
compare(new Plane()).with(new Plane()); // okay
以下將失敗:
compare(new Car()).with(new Plane()); // with(Car) can't be called with argument type Plane
不,無論有沒有泛型都無法實現。 從本質上講,您在詢問是否可以告訴編譯器違反多態的規則。
即使你明確定義了一個沒有泛型的方法,比如下面的方法,它仍然會接受擴展Vehicle
任何一對類。
void generateDiff(Vehicle maybePlane, Vehicle maybeCar) { ...
有一種情況是例外,但我不推薦它。 如果要針對擴展Vehicle
final
類對象(或任何未擴展的類)調用該方法,則可以覆蓋該方法以使每個參數的類簽名匹配。 但是你需要明確定義每一個。
class Vehicle;
final class Car extends Vehicle;
final class Plane extends Vehicle;
void generateDiff(Car car1, Car car2) { ...
void generateDiff(Plane plane1, Plane plane2) { ...
generateDiff(new Car(), new Car()); // OK
generateDiff(new Plane(), new Plane()); // OK
generateDiff(new Car(), new Plane()); // No matching method
我可以在編譯時使用泛型來實現這個目的嗎?
不是因為類型是在運行時設置的,但你可以簡單地使用內省並在函數發送無效類型時拋出異常,但如果是這樣的話那么它們可能是你設計中的一個缺陷,但這只是我的看法。
instanceof
運算符將檢查底層類型是什么,因此您可以引發異常或執行更合適的操作。
public <T extends Vehicle> generateDiff(T original, T copy)
因為你可能正在比較不同的類型,也許你不應該只有一個函數,因為它需要相當多的數量, if else
在每個類中相應地實現函數可能更明智,這樣它們就可以正確地與適當的對象進行比較類型,雖然我采取了相當數量的假設,這可能是錯誤的。
不,這是不可能的!
這就是我要做的:
class Vehicle;
class Car extends Vehicle;
class Plane extends Vehicle;
class DiffGenerator {
public Diff generateDiff(Car original, Car copy) {
return generateDiff(original, copy)
}
public Diff generateDiff(Plane original, Plane copy) {
return generateDiff(original, copy)
}
private Diff generateDiff(Vehicle original, Vehicle copy) {
return generatedDiff;
}
}
注意到私有方法? private Diff generateDiff(Vehicle original, Vehicle copy)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.