如何为 Java 中的灵活类型数组制作类型特定的比较器

How to make a type specific Comparator for a flexible type array in Java

我被困在 'generic-type-qualifier-land' 中间,找不到类型限定符的正确组合。我有一个 class 代表一个灵活的数组,其中可以有许多不同的类型。 class 持有一个 ArrayList<Object> 作为元素的容器。

class MyArray {
    ArrayList<Object>  list;

    ...

    public void sortAsString(Comparator<String> comp) {
        Collections.sort(list, comp);
    }
}

有类型特定的访问器,如 getString(i)getInt(i)

我希望能够以不同的方式对这个数组进行排序。有时数组中充满了字符串,我希望人们能够传入一个 Comparator<String> 对象。如果我如上所述声明 class,编译器会拒绝它,因为列表是 Object 的集合,而比较器是 Comparator<String>

但我也不会打字。这不起作用:

    public void sortAsString(Comparator<String> comp) {
        Coparator<Object> foo = (Comparator<Object>) comp;
        Collections.sort(list, foo);
    }

Collections.sort函数第二个参数需要Comparator<? super Object>。有什么方法可以声明方法 and/or 进行类型转换,以便有人可以传递 Comparator<String> 并让它在这个 ArrayList<Object> 上工作?

我也尝试将列表转换为 ArrayList<String>,但这也是不允许的。在调用它的情况下,用户将相当确定数组中只有字符串,但当然我们在编译时不知道这一点。我试图告诉它,即使它没有被声明为字符串数组,也可以像对待排序一样对待它。我不在乎当成员对象不是字符串时它是否会爆炸。我只是一些语法糖告诉编译器继续并让它调用排序方法。

只需使用原始类型。这编译

    public void sortAsString(Comparator<String> comp) {
        List<Object> list = null;
        Comparator foo = comp;
        Collections.sort(list, foo);
    }

假设您绝对确定 ArrayList<Object> 仅包含 String,并且您已做好崩溃的准备,如果那不是案例...

您可以从 Comparator<String> 创建一个 Comparator<Object>,如果将非 String 传递给它,它将崩溃:

Collections.sort(list, (x, y) -> comp.compare((String)x, (String)y));

我建议在此之前检查是否所有对象都是字符串,如果不是这样,则抛出一个有意义的异常message/do什么都没有。

您正试图将列表转换为 ArrayList<String>(或者可能只是 List<String>)。不过,编译器将此标记为错误,因为通常它绝对不安全。

如果调用者进行此调用是安全的,您可以使用“cast through raw”技术来避免编译错误。您仍然会收到未经检查的警告,然后您可以将其抑制。此外,在进行不安全转换之前检查列表的内容可能是个好主意。这允许您验证您正在做的事情实际上是安全的,或者如果不是,您可以以适当的方式将其传达给调用者——可能通过抛出异常。例如,

    public void sortAsString(Comparator<String> comp) {
        if (! list.stream().allMatch(o -> o instanceof String)) {
            throw new IllegalStateException("MyArray contains non-strings");
        }
        @SuppressWarnings("unchecked")
        ArrayList<String> temp = (ArrayList<String>)(ArrayList)list;
        temp.sort(comp);
    }