java8中的方法引用(双冒号)::是类似于C++的域运算符,获取方法使用的。
使用场景:cars.forEach( Car::repair );
1、构造方法引用(Class::new):
相当于创建对象;如果函数式接口方法有参数,会匹配具体有参构造方法。
2、静态方法引用(Class::static_method):
相当于ClassName.staticMethod(),如果有参数会把参数当方法的参数。
3、特定类任意对象方法引用(Class::method):
相当于new ClassName().method(),会把第一个参数当作类对象,来调用特定类的任意对象方法,其他参数当作方法的参数。
4、特定对象方法引用(instance::method):
相当于instance.method(),如果有参数,参数就是方法的参数。
特定类任意对象方法引用和特定对象方法引用本质上的区别就是:前者传入的参数第一位一定要是类对象(实例化对象),其他参数依次作为方法参数(自动匹配),后者已经存在类对象(自己实例化对象),所有参数都将作为方法参数(自动匹配类型)。两者实际都是通过实例化的类对象来调用方法的。
特点:
忽略名称:接口与接口抽象方法;
限制类型:具体对象引用方法的返回值类型和方法参数类型与接口抽象方法的返回值类型与参数类型一致。
构造方法引用:
public class T02 {
public static void main(String[] args) {
A a = C::new;//引用C的无参构造
a.test()
B b = C::new;//引用C的String类行的有参构造
b.test("this is B interface test method...");
}
}
interface A {
void test();
}
interface B{
void test(String s);
}
class C {
public C(){
System.out.println("--empty--constructor= ");
}
public C(String s){
this.a=s;
System.out.println("--not empty--constructor= "+s);
}
}
静态方法引用:
public class T02 {
public static void main(String[] args) {
//这里的C::accept方法对应的是Consumer函数接口中的accept方法,返回值类型和参数类型一致,
//实际就是对lambda表达式的简化,将lambda的语句体逻辑通过某个类的方法执行
Arrays.asList("a","c","b").forEach(C::accept);//实际对应的就是下面的匿名内部类方法。
//仔细观察就是省略了Consumer和accept等操作,直接实现Consumer.accept方法
Arrays.asList("a","c","b").forEach(new Consumer<String>() {
@Override
public void accept(String s) {
C.accept(s);
}
});
}
}
class C {
public static void accept(String s) {
System.out.println("this is static = "+s);
}
}
特定类任意任意对象方法引用:
public class T02 {
public static void main(String[] args) {
//特定类的任意对象方法引用实际就是特定对象的方法引用的无参表现
//非静态方法引用:
//特定类的任意对象方法引用:只有一个参数且正好是C
//特定对象的方法引用:如果第一个参数正好是C,第二个参数和accept方法的参数类型一致,那么也可以写作:C::accept,如果第一个参数不是C,那么只好自己new一个C来调用accept
Arrays.asList(new C(),new C(),new C()).forEach(C::accept);
}
}
class C {
public void accept(String s) {
System.out.println("test");
}
}
特定对象方法引用:
public class T02 {
public static void main(String[] args) {
Arrays.asList("a","b","c").forEach(new C()::accept);//因为只有一个参数String类型,不具备C类型,所以只能自己new C()来调用。
//如果正好有两个参数,一个是C类型,一个是String类型,那么可以直接写做:C::accept
//第一个C类型的参数会充当特定的对象,第二个String会作为accept的参数。等同于 c.accept
//非静态方法引用:
//特定类的任意对象方法引用:只有一个参数且正好是C
//特定对象的方法引用:如果第一个参数正好是C,第二个参数和accept方法的参数类型一致,那么也可以写作:C::accept,如果第一个参数不是C,那么只好自己new一个C来调用accept(string);
}
}
class C {
public void accept(String s) {
System.out.println("test s = " + s);
}
}
番外:<? extends T>和<? super T>
<? extends T> 表示类型的上界,表示参数化类型的可能是T 或是 T的子类
<? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是 T 或 T 的超类型(父类型),直至Object