为什么此lambda表达式使用与号强制转换?

问题描述

最近我偶然发现了Java Comparator类中的以下代码

public static <T,U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T,? extends U> keyExtractor)
{
    Objects.requireNonNull(keyExtractor);
    return (Comparator<T> & Serializable)
        (c1,c2) -> keyExtractor.apply(c1).compareto(keyExtractor.apply(c2));
}

让我感到困惑的是(Comparator<T> & Serializable)部分。由于该方法仅返回Comparator,因此在强制转换为Serializable时看不到它的用途。我也看不出以这种方式投放任何内容的原因,还是我错过了一些东西?

在我看来,如果我想将一个Object转换为多种可能的类型,则可以引入另一个通用类型,如下所示:

public static <T,U extends Comparable<? super U>,V extends Comparator<T> & Serializable> 
    V comparing(Function<? super T,? extends U> keyExtractor)
{
    Objects.requireNonNull(keyExtractor);
    return (V) (c1,c2) -> keyExtractor.apply(c1).compareto(keyExtractor.apply(c2));
}

通过这种方式,可以将返回值分配给Comparator或Serializable变量。

我能想到的唯一另一个原因是,将这种类型转换用作某种类型检查,以查看lambda表达式是否实际上返回了Serializable。

如果您有任何使用这种类型的转换的经验,或者对这种转换可以完成的想法有任何想法,将不胜感激。

解决方法

由于该方法仅返回Comparator,因此在转换为Serializable时看不到它的用途。

强制类型转换通知类型检查器返回的对象需要实现两个接口。创建lambda表达式结果的对象时将使用此信息。

在不进行强制转换的情况下,返回的Comparator对象仅实现{strong>仅的Comparator接口。如果比较器存储在可序列化对象的字段中,则会出现问题:

class MyClass implements Serializable {
     final Comparator<MyClass> comparator = Comparator.comparing(...)
}

如果现在序列化此类的实例,则比较器对象也将序列化。如果比较器对象没有Seri​​alizable接口作为超类型,则将获得异常。

,

&符定义了一个交集类型-您可以将其读为“需要同时实现SerializableComparator<T>接口的类”。

,

这种类型转换的怪异之处在于,它与Java中的所有其他类型转换不同:如果您在Java中像这样“投射” lambda表达式,则lambda实际上会实现Serializable(即,它不会只需更改编译器知道的类型,但是实际上会更改对象实现的类型!)

在这种情况下,类型转换的作用是为lambda表达式定义一个将匹配的目标类型。在这种情况下,目标类型是Comparator<T>Serializable的交集,这意味着在运行时lambda实例将实现这两​​个接口。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...