【问题标题】:Why is this lambda expression cast using an ampersand?为什么这个 lambda 表达式使用 & 符号转换?
【发布时间】:2020-12-02 06:38:57
【问题描述】:

最近我在 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&lt;T&gt; &amp; 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。

如果你们中的任何人对这种类型的演员有经验或知道这样的演员可以完成什么,我们将不胜感激。

【问题讨论】:

  • 您不能以您发布的方式将类型变量V 声明为返回类型。这就像承诺“调用者想要返回的任何类型,我都会做(只要该类型是Comparator&lt;T&gt;Serializable 的子类型)”。您不能返回未知的调用者选择的类型。

标签: java generics lambda casting ampersand


【解决方案1】:

由于该方法只返回一个 Comparator,我看不到转换为 Serializable 的用途。

强制转换告诉类型检查器返回的对象需要实现这两个接口。在创建作为 lambda 表达式结果的对象时会使用此信息。

没有强制转换,返回的Comparator 对象仅实现了Comparator 接口。如果比较器存储在可序列化对象的字段中,则会出现问题:

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

如果您现在序列化此类的实例,则比较器对象也会被序列化。如果比较器对象没有作为超类型的 Serializable 接口,则会出现异常。

【讨论】:

    【解决方案2】:

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

    在这种情况下,强制转换所做的是为 lambda 表达式定义一个 目标类型,它将匹配。本例中的目标类型是 Comparator&lt;T&gt;Serializable 的交集,这意味着运行时的 lambda 实例将实现这两​​个接口。

    【讨论】:

    • 感谢您的快速回答,我不知道 lambda 是这样工作的。
    【解决方案3】:

    & 符号定义了一个交集类型 - 您可以将其理解为“一个需要同时实现 SerializableComparator&lt;T&gt; 接口的类”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-07
      • 1970-01-01
      相关资源
      最近更新 更多