我写了一个帮助方法,将多个比较器合并为一个:
public static <T> Comparator<T> createComparatorChain( final Comparator<T>... comparators )
{
return new Comparator<T>()
{
public int compare( T lhs, T rhs )
{
for( Comparator<T> comparator : comparators )
{
int order = comparator.compare( lhs, rhs );
if( order != 0 )
{
return order;
}
}
return 0;
}
};
}
但如果我使用这种方法,那么我会得到一个未经检查的警告:
Collections.<File>sort( list, ComparatorUtils.<File>createComparatorChain( BY_FILE_DIRECTORY, BY_FILE_NAME ) );
类型安全:为varargs参数创建了一个通用的Comparator数组。
我的通用语法错误了吗?任何人都可以帮助我。
答案 0 :(得分:4)
我的通用语法错误了吗?
不,这只是关于如何实现Java泛型的另一个问题。基本上,数组和泛型类型不能很好地结合在一起。有关详细信息,请参阅Java generics FAQ。
在这种特殊情况下,我不是从数组构建链,而是从几个链接在一起的比较器构建链 - 每个都知道具有较高优先级的链和当前较低优先级的链。这避免了阵列。每个比较器只是要求其父进行比较,如果它不为零则直接返回结果,或者执行自己的比较并返回其他比较。 “顶部”比较器没有父级,因此只需执行自己的比较。
幸运的是,您甚至不需要自己编写 - 您可以Guava或ComparisonChain
使用Ordering.compound
。请注意,compound
的重载类似您的阵列版本,但需要Iterable<? extends Comparator<? super T>>
参数 - 是安全的。
答案 1 :(得分:1)
这是泛型和变种的经典问题。长话短说,这是因为varargs真的是阵列的语法糖。例如在这种情况下,comparators
的类型为Comparator<T>[]
。在调用站点,编译器创建一个正确类型的数组。当然,正如您所知,Java不允许您执行new Comparator<File>[]
,因此编译器会执行new Comparator<?>[]
并向您发出警告。
重要的是要知道只有在依赖comparators
的实际数组类型时才会出现“不安全”。如果你只需要迭代它的元素(正如你的方法所做的那样),那么它仍然非常安全。要以这种方式表明您的函数是安全的,如果您使用的是Java 7+,请在方法中添加@SafeVarargs
注释,警告将停止。