【发布时间】: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<T,S> 转换为T。
问题:如何以类型安全的方式实现这个apple.save()?
我不希望客户端代码中出现任何通配符,因此将abstract void setFood(T food); 更改为abstract <Z extends Food<T,S>> void setFood(Z food); 不是解决方案。 (显然我也在避免SupressWarnings("unchecked"))。
我知道 Java Generics, how to avoid unchecked assignment warning when using class hierarchy? 、 Generics cast issue 和 The get-put principle ,但我仍然无法理解它。
提前致谢!
【问题讨论】:
-
您要做的是将父类 obj 转换为子类 obj 现在这应该引发未经检查的警告,但是您需要传递一个扩展 Food 并将其转换为子类的参数像 Apple 或 Banana 这样的类 obj...如果我是你,我会
do void save() { getStorage().setFood(this);}并在每个类中覆盖此方法扩展食物。是的,更多的代码,但更可靠的设计:/ -
(感谢安德斯的编辑)
-
+1 到 @PaulBellora,因为叶类应该标记为
final。本质上,该问题的答案与 Meriton 的答案相同。
标签: java generics casting type-safety