Java 8 In Action之引用特定类型的任意对象的实例方法

此种引用类型名称原文为:reference to an instance method of an arbitrary object of a particular type

今天在和同学讨论另外一个问题的时候(直接导致这个问题只有明天再解决了),突然争论到能不能用类来调用实例方法,没想到由此又发现了一个知识盲区。
oracle官网文档和Java 8 In Action都没有怎么讲清楚这个问题。

方法引用总共有如下四种类型,这里只介绍第三种,其余三种都较为简单,如有需要,请参见他人博客。

 类型                                     示例

引用对象的实例方法 Object::instanceMethodName
引用类的静态方法  ClassName::staticMethodName
引用类的实例方法 ClassName::methodName
引用构造方法 ClassName::new

第三种引用类的实例方法???这个名字相当的不准确,在Java 8 In Action是这样介绍的,指向任意类型实例方法的方法引用(我觉得叫类的任意对象的实例方法引用更直观)。我开始一直想当然的就认为是类::实例方法这样就可以了,结果写了几个发现都用不了,看了官网给出的示例发现又可以,于是,作为当代优秀青年,怎么可能不解决这个问题呢。

官网给出的示例:

String [] stringArray = {“芭芭拉”,“詹姆斯”,“玛丽”,“约翰”,
    “Patricia”,“Robert”,“Michael”,“Linda”};
Arrays.sort(stringArray,String :: compareToIgnoreCase);


方法引用的等效lambda表达式String::compareToIgnoreCase将具有形式参数列表(String a, String b),其中a和b是用于更好地描述此示例的任意名称。方法引用将调用该方法a.compareToIgnoreCase(b)。我反正是没看懂这是讲的啥。之后再查了下,原文是这样的 “ reference to an instance method of an arbitrary object of a particular type ”  arbitrary 任意的, particular 特定的,翻译过来就是引用特定类型的任意对象的实例方法。于是乎,知道了类的实例方法调用是有讲究的。那么,有什么样的条件呢。

public class test1 {
    public static void main(String[] args) {

        List<Student> list = new ArrayList<>();
        list.add(new Student("Jack1", 88));
        list.add(new Student("Jack2", 81));
        list.add(new Student("Jack3", 82));
        list.add(new Student("Jack4", 83));
        list.add(new Student("Jack5", 84));
        list.add(new Student("Jack6", 85));
        list.sort(Student::compareByScore);
        System.out.println(list);
    }
}

class Student {
    private String name;
    private int score;

    public Student(){

    }

    public Student(String name,int score){
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int compareByScore(Student student){
        return this.getScore() - student.getScore();
    }

    @Override
    public String toString(){
        return this.name + "  " + this.score + "  ";
    }
}


list.sort接受一个Comparator,Comparator需要实现compare方法,lambda形式 (v1,v2)-> {dosth;return intval;}。这里的compareByScore就是这种lambda形式的方法引用。

如果将上面的compareByScore方法改成如下形式,为什么又要报错了,我不就多传了一个参数进去么,其他的啥也没做啊。

 public int compareByScore(Student student1, Student student2){
        return this.getScore() - student1.getScore();
    }


不好意思,它要求接口方法的参数必须比引用方法的参数多一个。而且第一个参数要是该引用方法的所在类型的或其父类,除接口方法的第一个参数以外, 其余参数的类型要求一样。这一段话,有些难以理解,看下面的代码就会明白了。

example 1

public  class Test1 {
    public void a(){
    }
    public static void main(String[] args) {
        MyInter m = Test1::a;
    }
}
@FunctionalInterface
interface MyInter {
    //入参参数比Test1的a方法多一个,且Test1::a的Test1与该入参类型Test1相同
    public void d(Test1 d);
}


example 2

public  class Test1 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {
        MyInter m = Test1::a;
    }
}
@FunctionalInterface
interface MyInter {
    //该接口参数比上述的a方法参数数量多一个,除去第一个,其它类型一致(可兼容,如可以一个int,一个Integer)
    //且Test1::a的Test1是该入参类型Test1相同
    public void d(Test1 d,int param1,int param2);
}

example 3
 

public  class Test1 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {
        MyInter m = Test1::a;
    }
}
class Test2 extends Test1 {
}
@FunctionalInterface
interface MyInter {
    //该接口参数比上述的a方法参数数量多一个,除去第一个,其它类型一致(可兼容,如可以一个int,一个Integer)
    //且Test1::a的Test1是该入参类型Test2的子类(不可颠倒)
    public void d(Test2 d,int param1,int param2);
}

example 4
 

public  class Test1 {
    public void a(Integer param1,int param2){
    }
    public static void main(String[] args) {
        MyInter m = (j,k,l)->j.a(k, l);
        //第一个参数为方法目标,其余参数为参数
    }
}
@FunctionalInterface
interface MyInter {
    public void d(Test1 d,int param1,int param2);
}

看到这你应该就懂了,这个指向任意类型实例方法的方法引用有两个要求:
       第一点:接口方法的参数比引用方法的参数多一个
       第二点:接口方法的第一个参数恰巧是调用引用方法的对象(其引用方法所在类或其父类的实例)
       如有不当之处,望指正。
参考文献:https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
                   https://stackoverflow.com/questions/32855138/how-does-a-method-reference-to-an-instance-method-of-an-arbitrary-object-of-a-p
                   https://stackoverflow.com/questions/25512532/instance-method-reference-and-lambda-parameters
                   https://segmentfault.com/a/1190000012269548
                   https://blog.csdn.net/qwe125698420/article/details/53415746
                   https://blog.csdn.net/learningcoding/article/details/72539918
                   https://blog.idrsolutions.com/2015/02/java-8-method-references-explained-5-minutes/
                  
 

猜你喜欢

转载自blog.csdn.net/weixin_41126303/article/details/81187002