如何处理通用接口实现并避免@SuppressWarnings?

时间:2019-07-12 12:21:51

标签: java generics

我试图对不同的服务实现进行通用处理,并且不断收到“由于原始类型而导致未经检查的呼叫”错误。

我尝试了几种实现方式,但不太了解这里的问题。

我有以下模型:

public abstract class Fruit {

  public List<String> vitamins;
  public String originCountry;

  // getters and setters omitted
}

具体实现如下:

public class Kiwi extends Fruit {
}

public class Pineapple extends Fruit {
}

我有以下界面:

public interface FruitCheckService<T extends Fruit> {

  List<String> compareVitaminsFromDifferentCountries(T firstFruit, T secondFruit);

  Class<T> getImplementation();
}

具有上述两个模型的实现:

@Service
public class KiwiCheckServiceImpl implements FruitCheckService<Kiwi> {

  @Override
  public List<String> compareVitaminsFromDifferentCountries(Kiwi firstFruit, Kiwi secondFruit) {
    // some implementation
    return new ArrayList<>();
  }

  @Override
  public Class<Kiwi> getImplementation() {
    return Kiwi.class;
  }
}

还有菠萝:

@Service
public class PineappleCheckServiceImpl implements FruitCheckService<Pineapple> {

  @Override
  public List<String> compareVitaminsFromDifferentCountries(Pineapple firstFruit, Pineapple secondFruit) {
    // some implementation
    return new ArrayList<>();
  }

  @Override
  public Class<Pineapple> getImplementation() {
    return Pineapple.class;
  }
}

我有以下用不同的bean操作的类:

@Service
public class FruitServices {

  private Map<Class, FruitCheckService> beansMap;

  @Autowired
  public FruitServices(List<FruitCheckService> fruitCheckServices) {

    beansMap = new HashMap<>();

    fruitCheckServices
      .forEach(
        fruitCheckService -> {
          Class implementation = fruitCheckService.getImplementation();
          beansMap.put(implementation, fruitCheckService);
        }
      );
  }


  public FruitCheckService getFruitCheckService(Class clazz) {
    return beansMap.get(clazz);
  }
}

最后,这是我称之为的服务:

@Component
public class BusinessService {

  @Autowired
  private FruitServices fruitServices;

  public void compareVitamins(Fruit one, Fruit two) {

    Class<? extends Fruit> aClass = one.getClass();

    FruitCheckService fruitCheckService = fruitServices.getFruitCheckService(aClass);

    List<String> result = fruitCheckService.compareVitaminsFromDifferentCountries(one, two);
  }
}

如何正确使用fruitCheckService而不以原始类型'exercise2.service.FruitCheckService'的成员的身份收到“未经检查的对'compareVitaminsFromDifferentCountries(T,T)的调用”?

1 个答案:

答案 0 :(得分:1)

问题是您在服务定义中使用了原始类型Class。要解决此问题,可以使用bounded wildcard type ?,如下所示:

class FruitServices {

  private Map<Class<? extends Fruit>, FruitCheckService<? extends Fruit>> beansMap;


  public FruitServices(List<FruitCheckService<? extends Fruit>> fruitCheckServices) {

    beansMap = new HashMap<>();

    fruitCheckServices
      .forEach(
        fruitCheckService -> {
          Class<? extends Fruit> implementation = fruitCheckService.getImplementation();
          beansMap.put(implementation, fruitCheckService);
        }
      );
  }

  public FruitCheckService<? extends Fruit> getFruitCheckService(Class<? extends Fruit> clazz) {
    return beansMap.get(clazz);
  }
}

对于类BusinessService,事情将变得更加棘手。首先,必须使compareVitamins为通用方法,以确保两个水果都属于同一类型。但是即使那样,我仍然认为您无法避免getFruitCheckService的结果导致的未经检查的转换,因为FruitServices必须处理针对不同类型水果的服务,因此您无法精确返回值getFruitCheckService的类型参数。

class BusinessService {

    private FruitServices fruitServices;

    public <T extends Fruit> void compareVitamins(T one, T two) {

        @SuppressWarnings("unchecked")
        FruitCheckService<T> fruitCheckService = 
            (FruitCheckService<T>) fruitServices.getFruitCheckService(one.getClass());

        List<String> result = fruitCheckService.compareVitaminsFromDifferentCountries(one, two);
    }
}