【问题标题】:Casting a generic superclass to a subclass将泛型超类转换为子类
【发布时间】:2013-05-22 10:48:18
【问题描述】:

这是我的第一个 SO 问题,我希望它对读者和我自己都足够有用!在过去的两天里,我在谷歌上搜索并避开了这个世界。

我有抽象模型和存储类,具体模型和存储类派生自这些类:

abstract class Food {}

abstract class FoodStorage<T extends Food> {
    abstract void setFood(T food);
}

class Apple extends Food {}

class Basket extends FoodStorage<Apple> {
    @Override
    void setFood(Apple apple) {
        // Save that apple to the basket
    }
}

没问题。现在,我希望能够直接在Apple 实例上调用save(),将其持久化到Basket(无需担心篮子),并在抽象类中实现它。我发现的最好的是:

abstract class Food<T extends Food<T,S>,
        S extends FoodStorage<T,S>> {

    abstract S getStorage();

    void save() {
        getStorage().setFood((T)this); // <---- Unchecked cast warning
    }

}

abstract class FoodStorage<T extends Food<T,S>, S extends FoodStorage<T,S>> {
    abstract void setFood(T food);
}

class Apple extends Food<Apple,Basket> {
    Basket basket = new Basket(); // or Basket.getInstance();

    @Override
    Basket getStorage() {
        return basket;
    }
}

class Basket extends FoodStorage<Apple,Basket> {
    @Override
    void setFood(Apple apple) {
        // Save that apple to the basket
    }
}

这可行,但 IntelliJ 警告我 save() 中未经检查的演员表。确实,我正在从Food&lt;T,S&gt; 转换为T

问题:如何以类型安全的方式实现这个apple.save()

我不希望客户端代码中出现任何通配符,因此将abstract void setFood(T food); 更改为abstract &lt;Z extends Food&lt;T,S&gt;&gt; void setFood(Z food); 不是解决方案。 (显然我也在避免SupressWarnings("unchecked"))。

我知道 Java Generics, how to avoid unchecked assignment warning when using class hierarchy?Generics cast issueThe get-put principle ,但我仍然无法理解它。

提前致谢!

【问题讨论】:

  • 您要做的是将父类 obj 转换为子类 obj 现在这应该引发未经检查的警告,但是您需要传递一个扩展 Food 并将其转换为子类的参数像 Apple 或 Banana 这样的类 obj...如果我是你,我会 do void save() { getStorage().setFood(this);} 并在每个类中覆盖此方法扩展食物。是的,更多的代码,但更可靠的设计:/
  • (感谢安德斯的编辑)
  • +1 到 @PaulBellora,因为叶类应该标记为 final。本质上,该问题的答案与 Meriton 的答案相同。

标签: java generics casting type-safety


【解决方案1】:

在食物及其储存之间存在相互依赖关系的设计似乎颇有问题。单向依赖将大大简化泛型:

class Food { ... }
class FoodStorage<F extends Food> {
    void setFood(F f);
}

但是如果你坚持相互依赖,你可以不用强制转换如下:

abstract class Food<F extends Food<F, S>, S extends FoodStorage<F, S>> {
    abstract F getThis();
    abstract S getStorage();

    void save() {
        getStorage().setFood(getThis());
    }
}
abstract class FoodStorage<F extends Food<F, S>, S extends FoodStorage<F, S>> {
    abstract void setFood(F food);
}

【讨论】:

  • 太棒了!我只是指这样的东西,但“这个”太棒了
  • 呸!我也会这么说的;)
  • 很好,谢谢@Muhammad。关于相互依赖,我并不特别喜欢它,我只是看不到任何其他实现apple.save() 的方式。如果几天前出现的建议没有相互依赖,我会将其作为答案,否则我将验证此答案为最终答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多