簡體   English   中英

為什么 Java generics 不允許返回它自己的類型,如果類型是從另一個 class 擴展而來的?

[英]Why does Java generics doesnot allow returning its own type if the type is extended from anotehr class?

我有擴展 RowMapper 的 DBMapper class。 我將其參數化,因為需要為兩個不同的不同數據集完成兩個不同的映射。 這是代碼:

public class DBMapper<T> extends RowMapper<T>{
 
 T t;

 @Override
 public T mapRow (ResultSet rs, int rowNum){
   return mapData(t, rs, rowNum);
 }

 private <T extends B> T mapData(T data, ResultSet rs, int rowNum){
   //TODO mapping operations for Class B
    return data;
 }

 private <T extends C> T mapData(T data, ResultSet rs, int rowNum){
  //TODO mapping operations for class C
   return data;
 }

在這里,我在 mapRow 方法的返回語句中遇到錯誤。 錯誤是

The method mapData(T extends B, ResultSet, int) in the type DBMapper<T> is not applicable for the arguments (T, ResultSet, int)

它返回有效的類型 T。 即使 T 正在擴展另一個 class,返回的仍然是類型 T。 為什么會出現上述錯誤?

方法 mapData() 中的類型參數 T 隱藏了您的原始類型參數。 您應該收到警告“類型參數 T 隱藏了類型 T”。 正如@Slaw 在評論中指出的那樣,此方法類型參數是一個全新的參數,獨立於原始 T,只是您給它起了相同的名稱,從而隱藏了另一個。

此外,Java Generics 的類型參數在運行時不再存在(關鍵字“類型擦除”)。 因此,即使您消除了此錯誤消息,不幸的是,僅使用 Java-Generics-syntax 也不可能在運行時區分 T 的類型。

因此,正如@Sweeper 所建議的那樣,您必須在不同的類中進行兩種不同的實現,或者您采用@beneboo22 的方法,您顯然更喜歡這種方法,並且只在一個返回類型為TmapData()方法中進行實例化檢查(沒有額外的類型參數):

private T mapData(T data, ResultSet rs, int rowNum){
     if (data instanceof B) {
         return data; //TODO implement map
     }
     if (data instanceof C) {
         return data; //TODO implement map
     }

     return data; // TODO implement default map
 }

@Sweeper 的解決方案看起來像:

public abstract class DBMapper<T> extends RowMapper<T>{
 T t;

 @Override
 public T mapRow (ResultSet rs, int rowNum){
   return mapData(t, rs, rowNum);
 }

 abstract T mapData(T data, ResultSet rs, int rowNum);
}

class BMapper extends DBMapper<B>{
     @Override
     B mapData(B data, ResultSet rs, int rowNum){
         return data; //TODO implement map
     }
}
class CMapper extends DBMapper<C>{
     @Override
     C mapData(C data, ResultSet rs, int rowNum){
         return data; //TODO implement map
     }
}

編輯: @dmitryvim 的回答似乎等同於我的 instanceof 方法。如果可以使用T.class而不是t.getClass()會有所不同,但由於類型擦除,前者在運行時是未知的了。)

public class DBMapper<T> extends RowMapper<T> {  


 T t;

 @Override
 public T mapRow (ResultSet rs, int rowNum){
   if (B.class.isAssignableFrom(t.getClass())) {
     return mapDataB(t, rs, rowNum);
   }
   if (C.class.isAssignableFrom(t.getClass())) {
     return mapDataC(t, rs, rowNum);
   }
   throw new IllegalArgumentException();
 }

 private <T extends B> T mapDataB(T data, ResultSet rs, int rowNum){
   //TODO mapping operations for Class B
    return data;
 }

 private <T extends C> T mapDataC(T data, ResultSet rs, int rowNum){
  //TODO mapping operations for class C
   return data;
 }

}
 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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