【问题标题】:Get elements with a certain generic type in a list获取列表中具有特定泛型类型的元素
【发布时间】:2020-02-13 18:30:15
【问题描述】:

我目前正在做一个火车项目,我有以下问题:

我将所有机车车辆保存在一个列表中: 为了更好地理解我的类层次结构,这里有一个简化的继承概述:

RollingStock
    Engine
        SteamEngine
        DieselEngine
        ...
    Coach
        FreightCoach
        PassengerCoach
        ...
    TrainSet

在我的寄存器中,我想将所有机车车辆保存在列表中 private List<RollingStock> rollingStock;。到目前为止,我已经为每种机车车辆类型(引擎、教练、火车组)创建了一个列表。但是,我需要删除某个机车车辆及其 ID,因此将所有内容保存在一个列表中会更容易。

和以前一样,我创建了一个这样的引擎:

    public void createEngine(Engine engine) {
        this.engines.add(engine);
    }

现在,只有一个列表,我这样做:

    public void createEngine(Engine engine) {
        this.rollingStocks.add(engine);
    }

这工作得很好。对于 returnEngines() 方法,我似乎没有找到解决方案:

每个机车车辆类型都有一个列表,就这么简单:

    public List<Engine> returnEngines() {
        return engines;
    }

现在,我必须从机车车辆列表中过滤掉所有引擎:

    public List<Engine> returnEngines() {
        ...
        return rollingStock.???;

    }

我可以添加方法public String getType() 并检查它的类型。

我无法想象没有更好的解决方案。

如何做到这一点?

【问题讨论】:

  • 你的股票列表中的股票顺序有什么价值吗?如果没有,我认为您最好使用Sets。我的另一个建议是,如果您想要引擎和机车车辆(等)的集合,您可以将机车车辆制作为合成集合,在内部由其他集合组成。
  • 使用Set 的优势是什么?它将如何解决我的问题?
  • 首先,您可以使用 Set 自动防止重复。另一方面,确认对象在集合内会更快。第三件事是,如果您不需要在组合集合上定义顺序,则可以更轻松地将基础集合(SteamEngines、DieselEngines 集合)组合在一个集合中。这如何帮助解决您的问题?使用一组基础集合,您可以将集合用于所有 RollingStock 的操作,但是当您只需要引擎时,您可以只使用该集合,而不必按照 Frisch 的回答进行过滤
  • 谢谢,这将解决我的问题。例如,当我列出所有火车(按其 ID)时,我还能对集合进行排序吗?我怎样才能合并我所有的集合? MergeSets() 只能用来合并两个集合,对吧?
  • 集合被定义为无序,排序没有意义。您可以做的是使用 List.addAll(...) 将集合中的所有内容添加到列表中以进行排序。至于合并,我建议您创建一个实现Set 的类,并使用属于您的较大Set 的一部分的其他集合来实现Sets 方法@

标签: java generics inheritance


【解决方案1】:

流式传输列表,过滤Engine 的实例;将实例从RollingStock 映射到Engine(带有演员表),将结果收集到新的List 中。喜欢,

public List<Engine> returnEngines() {
    return rollingStocks.stream().filter(x -> x instanceof Engine)
            .map(x -> (Engine) x).collect(Collectors.toList());
}

【讨论】:

  • 谢谢,但是使用 instanceof 是不好的编码风格,不是吗?我可以改用 getClass() 或 isInstance() 吗?
  • 在运行时检查类型是不好的,与其说是编码风格的问题。 .filter(Engine.class::isInstance) 也可以(但实际上与我发布的内容相同)。
【解决方案2】:

Elliott Frisch 的回答是完全有效的,这是一个通用的解决方案,以防您还需要一种方法来过滤您的任何类型的层次结构的寄存器:

public <T> List<T> returnClazz(Class<T> clazz) {
    return rollingStocks.stream()
            .filter(clazz::isInstance)
            .map(clazz::cast)
            .collect(Collectors.toList());
}

然后可以被几个辅助方法使用,例如

public List<TrainSet> returnTrainset() {
    return returnClazz(TrainSet.class);
}

public List<Engines> returnEngines() {
    return returnClazz(Engine.class);
}
...

也可以直接调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-25
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 2012-01-28
    • 1970-01-01
    相关资源
    最近更新 更多