【问题标题】:Generic interface and implementation - type cannot be converted通用接口和实现 - 无法转换类型
【发布时间】:2019-10-15 22:31:28
【问题描述】:

我有一个通用接口定义为:

public interface ItemService<T extends Slicer, E extends ItemSlice> {
    E getItemHistory(final String id, final T slicer);
}

还有一个实现:

public class DynamoDbItemService implements ItemService<DynamoDbSlicer, DynamoDbItemSlice> {
    public DynamoDbItemSlice getItemHistory(final String id, final DynamoDbSlicer slicer) {
    }
}

下面是上面提到的四个类的定义:

public interface Slicer {
    Map<String, ? extends Serializable> pointer();
}

public class DynamoDbSlicer implements Slicer {
    public Map<String, AttributeValue> pointer() {
    }
}

public interface ItemSlice extends Slice<Item> {
}

public interface Slice<T> {
    List<T> data();
    Slicer next();
}

public class DynamoDbItemSlice implements ItemSlice {
    publi ImmutableList<Item> data() {}
    public DynamoDbSlicer next() {}
}

我想引用ItemService 接口,但它要绑定到DynamoDbItemService 实现,所以我可以在必要时将其换掉,我可以这样做:

ItemService<? extends Slicer, ? extends ItemSlice> itemService = new DynamoDbItemService itemService();

但如果我尝试像这样使用itemService

ItemSlice slice = itemService.getItemHistory(itemId, DynamoDbSlicer.first(1));
slice = itemService.getItemHistory(itemId, slice.next());

我得到这两个编译错误:

Error:(231, 82) java: incompatible types: item.pagination.DynamoDbSlicer cannot be converted to capture#1 of ? extends pagination.Slicer

Error:(238, 62) java: incompatible types: pagination.Slicer cannot be converted to capture#2 of ? extends pagination.Slicer

我从this question 了解到,? 通配符不能相同,所以我的问题是 - 我可以做我想做的事 - 使用界面吗?如果是这样,怎么做?还是我处理不当?

我之前已经问过两个与此相关的问题,这对我有帮助(firstsecond

【问题讨论】:

  • 如果我们能得到所有相关的方法来调试它会很好。您在那里缺少很多方法,最值得注意的是DynamoDbSlicer.first()

标签: java generics inheritance types


【解决方案1】:

我看不出以下对您不起作用的原因:

ItemService<DynamoDbSlicer, DynamoDbItemSlice> itemService = new DynamoDbItemService();
ItemSlice slice = itemService.getItemHistory("",  new DynamoDbSlicer());

但是如果你想让代码尽可能模块化,你可以使用这个方法来执行一个未经检查的强制转换(有人说是邪恶的)并得到你想要的结果:

public static void main(String[] args) {

    ItemSlice slice = getMySlice(new DynamoDbItemService());
}

@SuppressWarnings("unchecked")
public static <T extends Slicer, E extends ItemSlice> E getMySlice(ItemService<T, E> service) {
    return service.getItemHistory("", (T) new DynamoDbSlicer());
}

当然还有将类型推断责任传递给存储值的实际字段的解决方案。我自己会选择这个解决方案,因为我认为它提供了最大的灵活性:

public class DynamoDbItemService<T extends Slicer, E extends ItemSlice> implements ItemService<T, E>

ItemService<DynamoDbSlicer, DynamoDbItemSlice> itemService = new DynamoDbItemService();
ItemSlice slice = itemService.getItemHistory("", new DynamoDbSlicer());

【讨论】:

    猜你喜欢
    • 2013-10-04
    • 1970-01-01
    • 1970-01-01
    • 2017-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-24
    • 1970-01-01
    相关资源
    最近更新 更多