有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java需要使用泛型将列表过滤到特定的子类

我有一个List包含一个特定的超类(比如Vehicle),我想写一个方法,返回列表中的对象,这些对象是特定子类(比如Car)的实例

到目前为止,我有这个,但它会生成一个典型的“未检查”操作编译器警告:

public <T extends Vehicle> List<T> getVehiclesOfType(Class<T> type) {
    List<T> result = new ArrayList<T>();

    for (Vehicle vehicle : getVehicles()) {
        if (type.isAssignableFrom(vehicle.getClass())) {
            result.add(type.cast(vehicle)); // Compiler warning here
            // Note, (T)vehicle generates an "Unchecked cast" warning (IDE can see this one)
        }
    }

    return result;
}

Warning: Note: Test.java uses unchecked or unsafe operations.

我对实现这一点的任何其他方法都没有意见(我在Collections中找不到任何东西,但可能有一些JDK方法可以做到),但理想情况下,它将提供以下接口:

List<Car> cars = getVehiclesOfType(Car.class);

不过,我想知道为什么在原始代码中收到编译器警告


共 (6) 个答案

  1. # 1 楼答案

    您可能需要将@SuppressWarning("unchecked")添加到方法中

  2. # 2 楼答案

    问题是编译器不够聪明,无法知道车辆属于“类型”类。这是一个运行时检查,编译器不会进行这种分析。有很多这样的情况。例如,我使用if(true)return;在调试过程中尽早退出函数。如果我使用just return,编译器会意识到存在无法访问的代码,但使用条件,编译器不会意识到不可能进入该分支

    考虑如果将条件替换为IF(false){),代码不可能抛出异常,但仍然包含不安全的转换。

    基本上,编译器会说,“我不能确认这是安全的,所以这取决于你是否知道自己在做什么。”你的代码没有被破坏,你只需要谨慎行事

  3. # 3 楼答案

    您会收到警告,因为编译器(或IDE)如果不理解isAssignableFrom()的含义,就无法知道强制转换是安全的。但是isAssignableFrom()不是一种语言特性,它只是一种库方法。就编译器而言,这和你说的一样

        if (type.getName().contains("Elvis")) {
            result.add(type.cast(vehicle));
        }
    

    然而,你知道isAssignableFrom()的意思,所以你知道它是安全的。这正是@SuppressWarnings所要面对的那种情况

  4. # 4 楼答案

    2件事:

    I would like to know why I was receiving a compiler warning on the original code, though.

    第一名: 看看课程代码:它确实为你隐藏了演员阵容。通常,对任意类型(T)的强制转换应该是一个警告,但不是类。cast实际上会检查并忽略编译器警告(胡说八道)

    public T cast(Object obj) {
        if (obj != null && !isInstance(obj))
            throw new ClassCastException();
        return (T) obj;
    }
    

    第二名 这就是说:泛型警告是第一件要禁用的事情。把旧代码和现在的代码混合在一起,不值得去警告,我也不在乎。我只是在等着看泛型如何减少ClassCastException,这可能只有一种情况是正确的:使用add代替addAll(put/putAll)

  5. # 5 楼答案

    这个怎么样

    if (type.isInstance(vehicle)) {
        result.add((T)(vehicle));
    }
    

    编译器还在这样抱怨吗


    但如果我是你,我会使用Guava,这将使你的方法成为一行:

    public <T extends Vehicle> List<T> getVehiclesOfType(Class<T> type) {
        return Lists.newArrayList(Iterables.filter(getVehicles(), type));
    }
    
  6. # 6 楼答案

    你在Vehicle上操作,Vehicle是一个超类,你试图降级到Vehicle的一个子类。这总是一个不安全的类型转换,会给你一个编译器警告

    因此,虽然可以在没有警告的情况下从Car强制转换为Vehicle(因为Car extends Vehicle),但编译器无法知道类型为Vehicle的变量实际上是一个car

    通过使用强制转换(通过使用(Car)cast(..)),您告诉编译器您知道得更好。 编译器讨厌人,但仍然会给你一个警告:)