这是Java错误吗?

时间:2019-01-17 09:50:13

标签: java

以下代码为什么可以通过编译阶段并正确运行?

我不明白两点: 首先,mapToLong方法接受这样的functionalInterface

@FunctionalInterface
public interface ToLongFunction<T> {

    /**
     * Applies this function to the given argument.
     *
     * @param value the function argument
     * @return the function result
     */
    long applyAsLong(T value);
}

但是类longValue的方法Numberpublic abstract long longValue(); 其次,方法longValue是抽象方法,但是可以将其作为参数传递给mapToLong方法,为什么呢?

代码如下:

package com.pay.screen;


import java.util.ArrayList;
import java.util.List;

public class MainTest {

    public static void main(String[] args)  {
        List<Long> list = new ArrayList<>();
        list.add(1L);
        list.add(2L);
        long sum = list.stream().mapToLong(Number::longValue).sum();
        System.out.println(sum);

    }
}

2 个答案:

答案 0 :(得分:3)

来自Javadoc of mapToLong

LongStream mapToLong(ToLongFunction<? super T> mapper)

由于流是Stream<Long>,所以mapToLong需要ToLongFunction<? super Long>

Number::longValue可以是ToLongFunction<Number>,即需要Number并返回long的东西。您可以将Long传递给ToLongFunction<Number>,因为所有Long也是Number。因此,ToLongFunction<Number>也是ToLongFunction<? super Long>

因此很好。

答案 1 :(得分:0)

这很好,可以按照指定的方式工作。

除了安迪(Andy)在this answer中所说的话:

看看JLS 15.13. Method Reference Expressions,我们可以看到

Number::longValue匹配第三种形式,即ReferenceType :: [TypeArguments] Identifier

这里没有任何内容表明该方法不能为abstract。现在,此方法是ToLongFunction<Number>,对于 mapToLong,正如安迪(Andy)所解释的。

但是如果我们将其分配给ToLongFunction<Double>,它甚至可以工作:

ToLongFunction<Double> f = Number::longValue;

请参见15.13.1. Compile-Time Declaration of a Method Reference

  

在第二个搜索中,如果P1,...,Pn不为空,并且P1是ReferenceType的子类型,则将方法引用表达式视为具有类型P2,...的参数表达式的方法调用表达式。 ..,Pn。[...]

P1Double,它是Number的子类型,所以很好。

只有一种形式无法引用abstract方法,那就是

  

如果方法引用表达式的形式为super :: [TypeArguments] Identifier或TypeName,则是编译时错误。 super :: [TypeArguments]标识符,并且编译时声明是抽象的。

也就是说,您明确要求从超类型调用方法,但是该超类型只有一个可以匹配的抽象方法。