-2

我目前正在 JDK 1.8 上学习 lambda 表达式。我遇到了一些我发现我不明白的代码。

这是代码:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.lang.Comparable;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args ) throws Exception
    {

        List<String> list = Arrays.asList("a", "b", "c");
        sort(list, Comparable::<String>compareTo);

    }

    interface MyComparable {
        public <T extends Comparable<T>> int compare(T obj1, T obj2 );
    }

    public static <T extends Comparable<T>> void sort(List<T> list, MyComparable comp) {

        int n = comp.compare("5","2");
        System.out.println(n);
    }

}

comp.compare("5", "3")最终执行"5".compareTo("2")。我的理解是编译器需要找到一个与签名相同的静态方法

public <T extends Comparable<T>> int compare(T obj1, T obj2 );

我已经创建了这样的方法并且它有效。我不明白为什么 java 编译器调用"5".compareTo("2"). 他们的方法符号不一样。

关于编译器为什么生成这种代码的任何信息?

4

2 回答 2

6

如果您正在尝试学习方法引用,您应该求助于某种学习材料,例如Oracle 的 Java 教程。在那里你会发现:

方法参考的种类

种类 例子
引用静态方法 ContainingClass::staticMethodName
引用特定对象的实例方法 containingObject::instanceMethodName
引用特定类型的任意对象的实例方法 ContainingType::methodName
对构造函数的引用 ClassName::new

所以你看,方法引用并不局限于static方法。

您的方法引用Comparable::<String>compareTo与“对特定类型的任意对象的实例方法的引用”类型匹配。

此时值得注意的是,您实际上是在引用该方法Comparable.compareTo,就好像您已经编写了Comparable::compareTo. 由于引用的方法本身没有类型参数,因此您的类型参数无效。例如,您可以编写Comparable::<Button>compareTo相同的结果。

引用的方法具有功能签名,因为它在调用one时(Comparable,Comparable) → int消耗两个s ,将第二个作为参数传递(并且它将返回一个)。这与您的功能签名相匹配ComparableComparable.compareToComparableComparableintinterface

interface MyComparable {
    public <T extends Comparable<T>> int compare(T obj1, T obj2 );
}

因此可以在这种情况下使用方法引用。

我已经简化了功能签名;实际上他们正在(T,T)→int使用<T extends Comparable<T>>,因此您只能使用此函数比较同一具体实现的两个实例。Comparable

于 2015-04-22T16:10:59.410 回答
3

因此,您想知道如何将签名与预期不同的方法引用作为 lambda 表达式发送。但它们不需要完全相同。基本上,只有参数列表返回类型很重要:

如果满足以下所有条件,则可以将 lambda 表达式分配给目标类型 T:

  • T 是功能接口类型

  • lambda 表达式与 T 的方法具有相同数量的参数,并且这些参数的类型相同

  • lambda 主体返回的每个表达式都与 T 的方法的返回类型兼容

  • T 方法的 throws 子句允许 lambda 主体抛出的每个异常

从这里(第 4 节)

您的compare()( String, String) 的参数列表可以与String#compareTo()( this, String) 的参数列表匹配,并且它们的返回类型也相同 ( int),因此当需要另一个时,可以将其用作 lambda。

于 2015-04-22T16:18:23.027 回答