为什么这个 lambda 表达式使用 & 符号转换?
Why is this lambda expression cast using an ampersand?
最近我在 Java 比较器 class 中无意中发现了以下代码:
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)
部分。由于该方法只有 returns 一个比较器,所以我看不到在转换为可序列化时的用途。我也看不出有什么理由以这种方式投射任何东西,还是我遗漏了什么?
在我看来,如果我想将一个 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 表达式是否实际上 returns 可序列化。
如果你们中的任何人有这种类型的转换经验或者知道像这样的转换可以实现什么,我们将不胜感激。
& 符号定义了一个交集类型——您可以将其理解为“需要同时实现 Serializable
和 Comparator<T>
接口的 Class”。
这种转换的奇怪之处在于它不同于 Java 中的所有其他转换:如果您在 Java 中“转换”这样的 lambda 表达式,lambda 将实际实现 Serializable
(也就是说,这不仅改变了编译器知道的类型,而且实际上改变了对象实现的类型!)
在这种情况下,转换所做的是为 lambda 表达式定义一个目标类型,它将匹配。本例中的目标类型是 Comparator<T>
和 Serializable
的交集,这意味着运行时的 lambda 实例将实现这两个接口。
Since the method only returns a Comparator I don't see the use in casting to Serializable.
强制转换告诉类型检查器被返回的对象需要实现这两个接口。创建作为 lambda 表达式结果的对象时会使用此信息。
没有转换,返回的 Comparator
对象实现 Comparator
接口 仅 。如果比较器存储在可序列化对象的字段中,则会出现问题:
class MyClass implements Serializable {
final Comparator<MyClass> comparator = Comparator.comparing(...)
}
如果您现在序列化此 class 的一个实例,比较器对象也会被序列化。如果比较器对象没有 Serializable 接口作为超类型,您将得到一个异常。
最近我在 Java 比较器 class 中无意中发现了以下代码:
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)
部分。由于该方法只有 returns 一个比较器,所以我看不到在转换为可序列化时的用途。我也看不出有什么理由以这种方式投射任何东西,还是我遗漏了什么?
在我看来,如果我想将一个 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 表达式是否实际上 returns 可序列化。
如果你们中的任何人有这种类型的转换经验或者知道像这样的转换可以实现什么,我们将不胜感激。
& 符号定义了一个交集类型——您可以将其理解为“需要同时实现 Serializable
和 Comparator<T>
接口的 Class”。
这种转换的奇怪之处在于它不同于 Java 中的所有其他转换:如果您在 Java 中“转换”这样的 lambda 表达式,lambda 将实际实现 Serializable
(也就是说,这不仅改变了编译器知道的类型,而且实际上改变了对象实现的类型!)
在这种情况下,转换所做的是为 lambda 表达式定义一个目标类型,它将匹配。本例中的目标类型是 Comparator<T>
和 Serializable
的交集,这意味着运行时的 lambda 实例将实现这两个接口。
Since the method only returns a Comparator I don't see the use in casting to Serializable.
强制转换告诉类型检查器被返回的对象需要实现这两个接口。创建作为 lambda 表达式结果的对象时会使用此信息。
没有转换,返回的 Comparator
对象实现 Comparator
接口 仅 。如果比较器存储在可序列化对象的字段中,则会出现问题:
class MyClass implements Serializable {
final Comparator<MyClass> comparator = Comparator.comparing(...)
}
如果您现在序列化此 class 的一个实例,比较器对象也会被序列化。如果比较器对象没有 Serializable 接口作为超类型,您将得到一个异常。