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);
不过,我想知道为什么在原始代码中收到编译器警告
# 1 楼答案
您可能需要将
@SuppressWarning("unchecked")
添加到方法中# 2 楼答案
问题是编译器不够聪明,无法知道车辆属于“类型”类。这是一个运行时检查,编译器不会进行这种分析。有很多这样的情况。例如,我使用if(true)return;在调试过程中尽早退出函数。如果我使用just return,编译器会意识到存在无法访问的代码,但使用条件,编译器不会意识到不可能进入该分支
考虑如果将条件替换为IF(false){),代码不可能抛出异常,但仍然包含不安全的转换。
基本上,编译器会说,“我不能确认这是安全的,所以这取决于你是否知道自己在做什么。”你的代码没有被破坏,你只需要谨慎行事
# 3 楼答案
您会收到警告,因为编译器(或IDE)如果不理解
isAssignableFrom()
的含义,就无法知道强制转换是安全的。但是isAssignableFrom()
不是一种语言特性,它只是一种库方法。就编译器而言,这和你说的一样然而,你知道
isAssignableFrom()
的意思,所以你知道它是安全的。这正是@SuppressWarnings
所要面对的那种情况# 4 楼答案
2件事:
第一名: 看看课程代码:它确实为你隐藏了演员阵容。通常,对任意类型(T)的强制转换应该是一个警告,但不是类。cast实际上会检查并忽略编译器警告(胡说八道)
第二名 这就是说:泛型警告是第一件要禁用的事情。把旧代码和现在的代码混合在一起,不值得去警告,我也不在乎。我只是在等着看泛型如何减少ClassCastException,这可能只有一种情况是正确的:使用
add
代替addAll
(put/putAll)# 5 楼答案
这个怎么样
编译器还在这样抱怨吗
但如果我是你,我会使用Guava,这将使你的方法成为一行:
# 6 楼答案
你在Vehicle上操作,Vehicle是一个超类,你试图降级到Vehicle的一个子类。这总是一个不安全的类型转换,会给你一个编译器警告
因此,虽然可以在没有警告的情况下从
Car
强制转换为Vehicle
(因为Car extends Vehicle
),但编译器无法知道类型为Vehicle
的变量实际上是一个car通过使用强制转换(通过使用
(Car)
或cast(..)
),您告诉编译器您知道得更好。 编译器讨厌人,但仍然会给你一个警告:)