此种引用类型名称原文为: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 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/