请解释 Java 8 方法引用实例方法使用 class 名称

Please Explain Java 8 Method Reference to instance Method using class name

public interface MyFunc<T> {

    boolean func(T v1, T v2);

}
public class HighTemp {

    private int hTemp;

    HighTemp(){

    }
    public HighTemp(int ht) {
        this.hTemp = ht;
    }

    boolean sameTemp(HighTemp ht2){
         return hTemp == ht2.hTemp;
    }

     boolean lessThanTemp(HighTemp ht2){
        return hTemp < ht2.hTemp;
    }
}
class InstMethWithObjRef {

    static <T> int counter(T[] vals, MyFunc<T> f, T v){
        int count = 0;

        for (int i = 0; i < vals.length; i++) {
            if(f.func(vals[i], v)) count++;
        }
        return count;
    }
    public static void main(String[] args) {
        int count;
        //Create an array of HighTemp objects.
        HighTemp[] weekDayHighs = {new HighTemp(89), new HighTemp(82),
                                   new HighTemp(90), new HighTemp(89),
                                   new HighTemp(89), new HighTemp(91),
                                   new HighTemp(84), new HighTemp(83)};
        count = counter(weekDayHighs, HighTemp::lessThanTemp,new HighTemp(89));     
        System.out.println(count);          
    }
}

请解释如何

  1. boolean sameTemp() 与函数接口中的 func() 兼容。
  2. sameTemp() 方法在 func() 上在功能接口中实现。
  3. count = counter(weekDayHighs, HighTemp::sameTemp, new HighTemp(89)); 正在工作

请分别解释所有点。

等价 HighTemp::lessThanTemp 的 lambda 表达式是

(highTemp1, highTemp2) -> {
     return highTemp1.lessThanTemp(highTemp2);
} 

这是 Java8 名为 Reference to an Instance Method of an Arbitrary Object of a Particular Type

的功能之一

考虑以下示例,

interface FIface<T> {
    int testMethod(T a, T b);
}

class Test2 {

    private String str;

    Test2(String str) {
        this.str = str;
    }

    int ok(Test2 test2) {
        System.out.println("Currnet String : "+ this.str);//Refer to t1
        System.out.println("Test String : "+test2.str);//Refer to t2
        return 0;
    }

}

public class Test {

    public static <T> int checkCall(T t1, T t2, FIface<T> fiFace) {
        //Here Test2 :: ok is equivalent to t1.ok(t2)
        return fiFace.testMethod(t1, t2);
    }

    public static void main(String[] args) {
        checkCall(new Test2("a"), new Test2("b"), Test2 :: ok);
    }

}

输出

Currnet String : a
Test String : b

注意这里 Test2 :: ok 即使 ok 方法不是静态的,调用也是有效的。

当您为功能接口调用方法 checkCall 时,您仍然有两个参数,即 t1t2,并且对于该有效的 lambda 表达式,参数可以是 (Test t1, Test t2) 所以你的方法 Test2 :: ok 在这里对调用有效。在内部它是这样工作的 t1.ok(t2).

因此,fiFace.testMethod(t1, t2); 将调用方法作为 t1.ok(t2)

首先,我不是专业程序员。我也很难理解所谓的“对特定类型的任意对象的实例方法的引用”我认为这可能对通过 google 搜索来到这里的人有所帮助。
借助lambda表达式,我稍微理解了一点。

在您的代码中 HighTemp::lessThanTemp 作为 Lambda 表达式看起来像 (x,y)->{x.lessThanTemp(y);} 用此 lambda 表达式替换方法引用会产生相同的结果。上面的 Lambda 表达式或方法引用都告诉接口方法要做什么。
当您使用方法引用时,它会告诉接口方法使用给定 class 中的引用方法来执行其功能。因此,如果您将 HighTemp::lessThanTemp 转换为英文单词,它听起来像是“implement the lessThanTemp method form the class HighTemp as implementation of the interface function ”。正如您可能已经注意到的那样,return 类型和参数类型应该是兼容的。否则无法实现接口。

我会为您提供另一个简单的示例代码。更多示例有助于理解这个概念。

interface myint{
    int returnit(Test t ,int y);
}
class Test{
    int x=0;
    public Test(int x){
        this.x=x;
    }

    public int addNumbers(int y){
        return x+y;
    }
    public int subtractNumbers(int y){
        return x-y;
    }

}

public class myclass{
    private static void myMethod(Test t,myint inf,int y){
        int x=inf.returnit(t, y);
        System.out.println(x+"");
    }
    public static void main(String[] args){
        myMethod(new Test(4),Test::addNumbers,7);
        myMethod(new Test(4),Test::subtractNumbers,7);
    }
}


输出为:

11
-3


这是我能想到的最简单的方法。查看 return 类型和参数类型如何使用上述句型进行匹配。花点时间吧。

这是界面

package learninglambdaexp;

@FunctionalInterface
public interface TempInterface {

    public boolean validTemp(Temperature temp);
}

这是class

package learninglambdaexp;

public class Temperature {

    private int temp;

    public Temperature(int temp) {
        this.temp = temp;
    }

    public boolean isEvenTemp() {
        return temp % 2 == 0;
    }

    public boolean isOddTemp(){
    return !isEvenTemp();
    }
}

这是 Class 与 Main 方法

package learninglambdaexp;

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

public class AnotherMainClass {

    public static void main(String[] args) {

        List<Temperature> tempCollection = new ArrayList<>();
        tempCollection.add(new Temperature(100));
        tempCollection.add(new Temperature(20));
        tempCollection.add(new Temperature(30));
        tempCollection.add(new Temperature(40));
        tempCollection.add(new Temperature(50));
        tempCollection.add(new Temperature(60));
        tempCollection.add(new Temperature(70));
        int k1 = countVariation(tempCollection, Temperature::isEvenTemp);
        //int k2 = countVariation(Temperature::lowTemp);
        System.out.println(k1);
        // System.out.println(k2); 
    }

    private static int countVariation(List<Temperature> tempCollection, TempInterface ti) {
        int count = 0;
        for (Temperature eachTemp : tempCollection) {
            if (ti.validTemp(eachTemp)) { // (eachTemp) -> {return eachTemp.isEvenTemp();};
                count++;
            }
        }
        return count;
    }
}

一个参数更容易理解

如果我错了,请纠正我,但我对这种类型的方法引用的看法(Reference to an Instance Method of an Arbitrary Object of a Particular Type)是当我们传递一个方法引用时,在本例中传递给 counter 方法,匿名 class 的实例实现了 MyFunc 接口被建造。然后,在这个匿名 class 中,我们覆盖传递两个参数的 func 方法。然后在func方法里面,lessThanTemp方法是这样调用的:

v1.lessThanTemp(v2); 

所以对我来说这个概念看起来像这样:

public class Demo {
    public static void main(String[] args) {
        AnonymousClass an = new AnonymousClass();
        System.out.println(an.apply(new SomeClass(3), 4));
    }
}
interface SomeInterface {
    int apply(SomeClass obj, int n);
}

class SomeClass {
    private int n;

    SomeClass(int n) {
        this.n = n;
    }

    int add(int n) {
        return this.n + n;
    }
}
class AnonymousClass implements SomeInterface {

    @Override
    public int apply(SomeClass o, int n) {
        return o.add(n);
    }
}