java - Java - 铸造 Set 的缺点?
问题描述
我正在用 Java 开发一个基本的基于实体组件系统的游戏引擎,以获得乐趣。
我需要一种快速的方法来获取Component
某种类型的所有 s。例子:
public class MovementSystem extends System {
@Override
public void update() {
Set<Location> locations = ComponentManager.getActiveComponents(Location.class);
for (Location locationComponents : locations) {
// do stuff
}
}
}
所以我有一个ComponentManager
应该处理这个的:
public class ComponentManager {
private static final Map<Class<? extends Component>, Set<Component>> active = new HashMap<>();
public static void activate(Component component) {
// if component.class does not have an entry in
// active yet, initialize with new HashSet
active.computeIfAbsent(component.getClass(), compClass -> new HashSet<>());
active.get(component.getClass()).add(component);
}
public static void deactivate(Component component) {
Set<Component> comps = active.get(component.getClass());
if (comps != null)
comps.remove(component);
}
public static <T extends Component> Set<T> getActiveComponents(Class<T> compClass) {
return (Set<T>) active.get(compClass);
}
}
我的 IDE 不喜欢(Set<T>) active.get(compClass);
(以黄色突出显示)。然而,这是基于非常基本的测试,并且比单独铸造每个项目Set
并将它们添加到新的更快Set
,但是这样做的潜在缺点是什么?
解决方案
您看到的 IDE 警告是未经检查的转换。
在这里,您将返回分配getActiveComponents()
给 a Set<Location>
:
Set<Location> locations = ComponentManager.getActiveComponents(Location.class);
但是根据对象的来源,它可能是任何类型的Component
s (你从 a 中获取Set<Component>
),不一定Location
是 s :
private static final Map<Class<? extends Component>, Set<Component>> active = new HashMap<>();
当你使用它时:
return (Set<T>) active.get(compClass);
但是这样做的潜在缺点是什么?
今天,您的代码是正确的,因为它在Map
条目中添加了值,其中对象Set
具有用作键的类的运行时类型。
但是,如果稍后代码在映射中添加了不遵循此规则的内容,编译器将无法检测到打字错误。
所以你只会在运行时发现它:这是缺点。
你的情况不好吗?这取决于。
当您开发某种按类型/类别操作/分组对象的库时,可能会发生这种问题。您通常必须研究类型安全和代码灵活性/可维护性之间的平衡。
在这里,您“失去”类型安全性以减少维护结构的数量。
如果您的子类数量有限Component
并且它不会移动,则可以将地图分解为几组:每个子类一组。这样,您将不再有未经检查的转换。
但如果数量Component
子类很重要并且它会移动(您可以随时添加或删除它),未经检查的转换警告可能是可以接受的。在这种情况下,非常欢迎编写一个单元测试来确保您只检索预期类型的实例,因为这样可以保证当您执行未经检查的转换时编译器无法为您执行此操作。
推荐阅读
- javascript - 使用 mapData 的动态映射属性
- apache-spark - 如何使用 spark-cassandra-connector 将数据集写入 Cassandra 表?
- c# - Registry.LocalMachine.OpenSubKey() 返回与注册表编辑器不同的结果
- laravel - 这两个步骤是什么,在这个中间件中被检查了?
- javascript - 如何修复“TypeError:背景为空”?
- java - 使用反射将可见的 false 设置为按钮,可能吗?
- c# - VisualState 故事板未在路径“鼠标悬停”状态下激活
- android - TabHost 内的导航
- javascript - 从体内设置 iframe 高度
- python - 一起使用键盘模块和乌龟的问题