[英]How to write a generic method that takes two arguments of the same types in java?
當我注意到以下代碼編譯時沒有警告並打印Integer / String
時,我感到非常驚訝:
public final class GenericsTest {
private static <T> void method(T arg1, T arg2) {
System.out.println(arg1.getClass().getSimpleName());
System.out.println(arg2.getClass().getSimpleName());
}
public static void main(String[] args) {
method(1, "1");
}
}
我預計會出現編譯錯誤。
這段代碼編譯有什么原因嗎?
確保參數具有相同類型的正確方法是什么?
編輯:有界類型參數怎么樣? 我能想到的最好的是這樣的:
private static <T, U extends T> void method(T arg1, U arg2) {
System.out.println(arg1.getClass().getSimpleName());
System.out.println(arg2.getClass().getSimpleName());
}
不幸的是,java 不允許循環約束。 <T extends U, U extends T>
不能編譯。 這是一個死胡同嗎?
這個編譯的原因是因為 Java 會推斷傳入參數的最具體的超類型,在這種情況下, Object
Serializable & Comparable<? extends Serializable & Comparable<? extends Comparable<?>>>
Serializable & Comparable<? extends Serializable & Comparable<? extends Comparable<?>>>
Serializable & Comparable<? extends Serializable & Comparable<? extends Comparable<?>>>
,在1
被裝箱為Integer
並且"1"
作為String
傳遞之后。
沒有泛型:
private static void method(Number arg1, Number arg2) {
即使沒有泛型,您也可以傳入一個Integer
和一個Double
。
只有當有問題的類型是final
時,你才能做到這一點,沒有泛型:
private static void method(String arg1, String arg2) {
// Yes, they're both Strings, guaranteed.
我可以想到一種泛型的邊緣情況,以確保它們是確切的類型。 如果你有一個final
類,並且你設置了一個上限,那么你可以將它限制在同一個類中。
public <T extends MyFinalClass> void method(T arg1, T arg2) {
// Yes, they're both MyFinalClasses
}
但是你可以在沒有泛型的情況下做同樣的事情。
public void method(MyFinalClass arg1, MyFinalClass arg2) {
// Yes, they're both MyFinalClasses
}
您可以將該類添加為附加參數。
private static <T> void method(T arg1, T arg2, Class<T> type) {
// ...
}
現在您必須指定通用類型。
你仍然可以調用method(1, "1", Object.class);
但至少你是明確的公共類型。
這是不可能的。 或者換個角度來看,兩個引用參數總是“相同類型”—— Object
任何引用類型的參數總是Object
實例。
T
始終可以是Object
,並采用任意兩個引用參數。 即使使用<T, U extends T> void method(T arg1, U arg2)
, T
和U
都可以是Object
,因此再次采用任意兩個參數。
這樣做的根本原因是沒有類型安全的理由來設置這樣的約束。 繼承的要點之一是應該可以安全地像對待超類實例一樣對待子類實例。 超類類型的引用類型可以自由地指向該類或子類的實例。 因此,具有相同編譯時類型的兩個引用變量始終可以在運行時完全安全地指向不同子類類型的實例。 因此,在編譯時,除了它們是編譯時類型的子類之外,您永遠不能就兩個實例的實際運行時類的關系做出任何聲明。 由於兩個參數在運行時作為不同類的實例是安全的,因此實際傳遞不同編譯時類型的兩個參數也同樣安全。
這就是我解決這個問題的方法 - 我想創建一個方法來創建兩個對象的差異。
public List<Change> getChanges(Object o1, Object o2);
自然地,我希望 o1 和 o2 都屬於同一類型。 我通過將此方法封裝在參數化類中解決了這個問題。
public class DiffGenerator<T> {
public List<Change> getChanges(T o1, T o2) {
//code
}
}
這可以用作: List<Change> changes = new DiffGenerator<MyClass>().getChanges(myClassOld, myClassNew);
為我工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.