这是我的第一个SO问题,希望对读者和我自己都有足够的用处!我已经在过去两天里通过谷歌和DuckDuckGo搜索了世界各地的相关内容。
我有抽象模型和存储类,从中派生出具体的模型和存储类:
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);
不是解决方案。(显然也要避免使用SuppressWarnings("unchecked")
)。我知道这篇文章Java Generics, how to avoid unchecked assignment warning when using class hierarchy?,还有这篇文章Generics cast issue,以及这本书The get-put principle,但我仍然无法理解。
提前感谢!
do void save() { getStorage().setFood(this);}
并在每个扩展food的类中覆盖此方法。是的,代码更多了,但设计更加稳固 :/ - Muhammad Bekettefinal
。实质上,那个问题的答案与 meriton 的相同。 - wehlutyk