java - 如何维护依赖于每个具体实现的异构类型的集合?
问题描述
尽管Java的类型擦除,我试图找到一种方法来维护多个集合中的异构类型。
具体来说,如果我有几个接口
public interface Fuel {};
public interface Engine<T extends Fuel> {
public void burn(T fuel);
}
我希望能够将一组燃料和一组引擎放在一起。这样我就可以将每个发动机的燃烧称为正确的燃料类型。
class PowerPlant {
List<Engine<?>> engines;
List<Fuel> fuels;
public void run() {
fuels.stream().forEach(fuel -> {
engines
.filter(/* Not where I need help. */)
.burn(fuel); // This cast is my problem
});
}
}
以上因有趣的类型不匹配而失败
The method burn(capture#24-of ?) in the type Engine<capture#24-of ?> is not applicable for the arguments (Fuel<capture#25-of ?>)
有没有办法恢复类型让编译器开心?
(这就是我的问题的结尾,下面的一切都是我尝试过的不同的东西。)
我发现实际编译的最糟糕的选择是拥有一个元容器。
public class FuelEngine<T extends Fuel, S extends Engine<T>> {
public T fuel;
public S engine;
public void burn() {
engine.burn(fuel);
}
}
然后我可以将其构建到我的PowerPlant
public class PowerPlant {
List<FuelEngine<?, ?>> fuelEngines;
public void run() {
fuelEngines.stream().forEach(FuelEngine::burn);
}
}
但是我有更多的方法,而不仅仅是烧录(例如,,,burnFast
等burnSlow
)mixFuel
,并且真的不想为每个引入内部的新方法复制粘贴一堆“虚拟”方法Engine
。
我尝试过的失败或同样没有编译或更糟的事情(IMO)。
- “动态”铸造
public interface Engine<T extends Fuel> {
public void burn(T fuel);
public Class<T> getFuelType();
}
接着
public class PowerPlant {
List<FuelEngine<?, ?>> fuelEngines;
public void run() {
fuelEngines.stream().forEach(fuelEngine -> {
Engine<?> engine = fuelEngine.getEngine();
engine.burn(engine.getFuelType().cast(fuelEngine.getFuel()));
});
}
}
给出错误
The method burn(capture#19-of ?) in the type Engine<capture#19-of ?> is not applicable for the arguments (capture#20-of ?)
- 有一个类型化的方法
public PowerPlant {
List<FuelEngine<?, ?>> fuelEngines;
public void run() {
fuelEngines.stream().forEach(fuelEngine -> burn(fuelEngine.getFuel(), fuelEngine.getEngine());
}
public <T extends Fuel, S extends Engine<T>> void burn(T fuel, S engine) {
engine.burn(fuel);
}
}
给出错误
The method burn(T, S) in the type PowerPlant is not applicable for the arguments (capture#26-of ?, capture#28-of ?)
- 自定义异构类型安全容器
class FuelContainer {
Map<Class<?>, List<? extends Fuel>> fuelByType;
public <T extends Fuel> List<T> getFuels(Class<T> type) {
return fuelByType.get(type).stream().map(type::cast).collect(Collectors.toList());
}
}
随着PowerPlant
实施
public class PowerPlant {
public List<Engine<?>> engines;
public FuelContainer fuelContainer;
public void run() {
engines.stream().forEach(engine -> {
fuelContainer.getFuels(engine.getFuelType()).stream().forEach(engine::burn);
});
}
}
给出两个错误!
The method forEach(Consumer<? super capture#33-of ?>) in the type Iterable<capture#33-of ?> is not applicable for the arguments (engine::burn)
The type Engine<capture#34-of ?> does not define burn(capture#33-of ?) that is applicable here
- 接受
Engine
并Object
做自己的演员。
public interface Engine {
public void burn(Object fuel);
}
但这只是……丑陋,而且我的编译器失去了类型安全性。
- 有一堆类型的列表
public class PowerPlant {
List<ElectricEngine> electricEngines;
List<GasEngine> gasEngines;
List<Electricity> electricies;
List<GasFuel> gasFuels;
}
但是当我将拥有大约 30 种不同的发动机和燃料时,这并没有规模。
解决方案
我完全忘记了原始类型是一回事!
我已经用我的过滤器验证了正确Fuel
的发送到正确的位置。Engine
在引擎列表上使用原始类型只会导致编译器发出警告(而不是错误)。那些可以忽略,现在一切都像我想要的那样工作!
@SuppressWarnings({ "rawtypes", "java:S3740", "unchecked" })
class PowerPlant {
List<Engine> engines; // Warning raw type
List<Fuel> fuels;
public void run() {
fuels.stream().forEach(fuel -> {
engines
.filter(/* snip */)
.burn(fuel); // Warning type safety
});
}
}
朋友之间有几个@SuppressWarnings?
推荐阅读
- algorithm - 分析递归算法
- java - Java Hibernate 无效映射异常
- amazon-web-services - cloud-init cc_mounts.py 忽略 AWS EFS 挂载
- vba - Excel 错误 1004 用于特殊粘贴
- php - Twig 2 数组和 For 循环
- c - 当描述符重叠时,C11 数组初始化的行为是什么?
- java - 无法获取测试代码以使用 gradle 查找源代码
- html - css on focus 改变另一个 div 的样式
- python - Python十进制值处理
- c# - 如何在 c# 中列出所有带有 oid 的 Microsoft CA 证书模板