关于java8的方法引用
今天偶然看到一段代码
//首先有一个Studeng类 有一个静态方法,有个实例方法
class Student{
class Student {
private String name;
public Student(){
}
public Student(String name){
this.name = name;
}
//实例方法 say()
public void say() {
System.out.println(name);
}
//静态方法 say2()
public static void say2(String name) {
System.out.println(name);
}
}
注意:lists2.forEach(Student::say);
Student是类名, say() 是实例方法;
这里就是我的疑问,为什么可以调用实例方法呢?不应该通过对象调用吗??
List<Student> lists2 = Arrays.asList(newStudent("张三"),new Student("李四"));
lists2.forEach(Student::say);
//注意 这里Student是类名,调用的是实例方法say(),这里就是我的疑问,为什么可以调用实例方法呢?不应该通过对象调用吗??
lists2.forEach(Student::say); 为啥这里可以调用类的实例方法呢?
于是乎,我又写了一个例子,我把List的泛型里面的类型改成:String,
结果:发现如果在调用say()实例方法就会编译器报错;
这里就必须调用静态方法say2()静态方法才行!
那就奇了怪了,为啥一个可以调用,一个编译报错
改成静态方法就可以了
List<String> lists = new ArrayList<>();
lists.forEach(Student::say2);
//这里就必须调用静态方法了,否则的话编译器会报错!如上图
那这是为什么呢?上面的为什么可以通过类调用实例方法呢?
我们都知道 :类是优先于实例存在的,我们new()一个对象,必须要先加载类!
大家可以看到这两个方法唯一的区别就是list 里面的类型
一个是Student类,一个是String 类,类型不同
所以我就去看了java8的文档,终于解决我的疑问了;
以下摘自java8文档:
引用与Java8文档内容:
如何构建方法引用方法引用主要有三类。
(1) 指向静态方法的方法引用(例如Integer的parseInt方法,写作Integer::parseInt)。
(2) 指向任意类型实例方法的方法引用(例如String的length方法,写作String::length)。
(3) 指向现有对象的实例方法的方法引用(假设你有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例方法getValue,那么你就可以写expensiveTransaction::getValue)。第二种和第三种方法引用可能乍看起来有点儿晕。类似于String::length的第二种方法引用的思想就是你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。例如,Lambda表达式(String s) -> s.toUppeCase()可以写作String::toUpperCase。但第三种方法引用指的是,你在Lambda中调用一个已经存在的外部对象中的方法。
方法引用的三类
分析:
(1):指向静态方法的方法引用:就是 类名::静态方法
List<String> lists = new ArrayList<>();
lists.forEach(Student::say2);
//类名:Student::静态方法:say2,这个很好理解
(3) :指向现有对象的实例方法的方法引用:就是 对象::实例方法
List<String> lists = new ArrayList<>();
Student stu = new Student();
lists.forEach(stu::initMethod);
//已存在的外部对象:student的实例方法:initMethod
//这个也很好理解,就是调用对象的方法 对象::实例方法
上面两个都是很好理解的,跟我们理解的一样,类调用静态方法,对象调用实例方法,第二种就是上面遇到的情况
(2) :****☆指向任意类型实例方法的方法引用:
你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。例如,Lambda表达式(String s) -> s.toUppeCase()可以写作String::toUpperCase。因为String类型是lambda的一个参数
但第三种方法引用指的是,你在Lambda中调用一个已经存在的外部对象中的方法。
List<Student> lists2 = Arrays.asList(newStudent("张三"),new Student("李四"));
lists2.forEach(Student::say);
**//所以这里我们就应该明白为什么可以调用实例方法了,
因为我们的Student类型是lambda的一个参数,
所以才可以调用Student的实例方法**
补充一个例子,害怕大家没有理解
List<String> lists = new ArrayList<>();
lists.forEach(String::length);
//String的length方法并不是静态方法,为什么可以调用,是因为String类型是lambda的一个参数,所以可以调用
String的length方法并不是一个静态方法,为什么可以类名:: zh这样的形式调用,主要是 因为String是lambda的一个参数,所以可以调用String的实例方法
总结
因为我们的Student对象是lambda的一个参数,所以才可以调用实例方法