为什么要使用 ‘&’ 来转换这个 lambda 表达式?

huangapple go评论72阅读模式
英文:

Why is this lambda expression cast using an ampersand?

问题

Here's the translated code without any additional content:

最近我在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。我也不明白为什么要以这种方式强制转换任何东西,或者我漏掉了什么吗?

在我看来,如果我想要将一个对象强制转换为多种可能的类型,我可以像这样引入另一个泛型类型:

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。

如果你们有这种类型的强制转换的经验或者知道这样的强制转换能够实现什么目的,任何帮助都将不胜感激。

英文:

recently I stumbled over the following code in the Java Comparator class:

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

What's confusing me is the (Comparator&lt;T&gt; &amp; Serializable) part. Since the method only returns a Comparator I don't see the use in casting to Serializable. I also don't see the reason to ever cast anything this way, or am I missing something?

It seems to me that if I wanted to cast an Object to multiple possible types, I could just introduce another generic type like this:

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

This way the returned value could be assigned to both Comparator or Serializable variables.

The only other reason I could think of, is to use that cast as some kind of typecheck to see if the lambda expression actually returns a Serializable.

If any of you have experience with this kind of cast or an idea what casting like this could accomplish, any help would be appreciated.

答案1

得分: 3

> 由于该方法仅返回一个比较器(Comparator),我认为将其强制转换为Serializable没有意义。

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

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

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

如果现在对该类的实例进行序列化,比较器对象也会被序列化。如果比较器对象没有作为Serializable接口的超类型,将会引发异常。

英文:

> Since the method only returns a Comparator I don't see the use in casting to Serializable.

The cast tells the type checker that the object being returned needs to implement both interfaces. This information is used when creating the object which is the result of the lambda expression.

Without the cast, the returned Comparator object implements the Comparator interface only. This is a problem if the comparator is stored in a field of a serializable object:

class MyClass implements Serializable {
     final Comparator&lt;MyClass&gt; comparator = Comparator.comparing(...)
}

If you now serialize an instance of this class, the comparator object gets serialized too. If the comparator object doesn't have the Serializable interface as a supertype, you will get an exception.

答案2

得分: 2

The ampersand defines an intersection type - You can read it as "a Class that needs to implement both the Serializable and the Comparator<T> interface".

英文:

The ampersand defines an intersection type - You can read it as "a Class that needs to implement both the Serializable and the Comparator&lt;T&gt; interface".

答案3

得分: 1

这种类型的转换很奇怪,与Java中的所有其他转换不同:如果在Java中像这样“转换”一个lambda表达式,那么lambda将实际实现Serializable(即这不仅仅改变了编译器知道的类型,而且实际上改变了对象实现的类型!)

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

英文:

The weird thing about this kind of cast is that it's different from all other casts in Java: If you "cast" a lambda expression like this in Java the lambda will actually implement Serializable (i.e. this doesn't just change the type the compiler knows about, but actually changes what types the object implements!)

What the cast does in this case is define a target type for the lambda expression, that it will match. The target type in this case is the intersection of Comparator&lt;T&gt; and Serializable, meaning the lambda instance at runtime will implement both of those interfaces.

huangapple
  • 本文由 发表于 2020年8月12日 21:41:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/63377790.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定