简体   繁体   English

为什么 Java generics 不允许返回它自己的类型,如果类型是从另一个 class 扩展而来的?

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

I have the DBMapper class that extends RowMapper.我有扩展 RowMapper 的 DBMapper class。 I parameterized it since two different mappings need to be done for two different different data sets.我将其参数化,因为需要为两个不同的不同数据集完成两个不同的映射。 here is the code:这是代码:

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;
 }

Here I am getting an error in the return statement of mapRow method.在这里,我在 mapRow 方法的返回语句中遇到错误。 The error is错误是

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

It is returning the type T which is valid.它返回有效的类型 T。 Even if T is extending another class, still it is type T that is returned.即使 T 正在扩展另一个 class,返回的仍然是类型 T。 Why am I getting the above error?为什么会出现上述错误?

Your type parameters T in the methods mapData() are hiding your original type Parameter.方法 mapData() 中的类型参数 T 隐藏了您的原始类型参数。 You should get a warning "The type parameter T is hiding the type T".您应该收到警告“类型参数 T 隐藏了类型 T”。 As @Slaw pointed out in a comment, this method type parameter is an entirely new parameter, independent from the original T, just that you gave it the same name and thus hiding the other.正如@Slaw 在评论中指出的那样,此方法类型参数是一个全新的参数,独立于原始 T,只是您给它起了相同的名称,从而隐藏了另一个。

Furthermore the type parameters of Java Generics are not present anymore at runtime (keyword 'type erasure').此外,Java Generics 的类型参数在运行时不再存在(关键字“类型擦除”)。 Therefore, even when you get rid of this error-message, this kind of case distinction between the types of T at runtime is unfortunately not possible using only the Java-Generics-syntax.因此,即使您消除了此错误消息,不幸的是,仅使用 Java-Generics-syntax 也不可能在运行时区分 T 的类型。

So either, as @Sweeper suggested, you have to make two different implementations in different classes, or you take the approach by @beneboo22 which you apparently prefer and do the instanceof-checking in only one single mapData() method with return type T (no additional type parameter):因此,正如@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 's solution instead would look like: @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
     }
}

( Edit: @dmitryvim 's answer seems equivalent to the instanceof approach to me. It would be different, if one could use T.class instead of t.getClass() , but because of type erasure, the former is not known at runtime anymore.) 编辑: @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