目录

  • 用 :: 引用方法
  • 1. 4 种不同方法的引用
  • 2. 常见使用情景
  • a. 打印流:基于静态方法的引用
  • b. 在泛型中的使用
  • i. 引用方法
  • ii. 引用构造方法
  • 3. 与 Lambda 的比较



用 :: 引用方法

  • Java 中,可以用 :: 对方法和构造方法进行引用,借以改变指定对象的方法;
  • 方法引用通过方法的名字来指向一个方法;
  • 方法引用可以使语言的构造更紧凑简洁,减少冗余代码;

1. 4 种不同方法的引用

  • 可以直接引用类的构造方法、静态方法和特定对象的方法、特定类的任意对象的方法;
import java.util.Arrays;
import java.util.List;

//函数式接口(接口有且仅有一个抽象方法)
@FunctionalInterface
interface Supplier<T> {
    T get();//代表创建行为,但只能创建固定的东西,所以很少使用
}

class Car {
    public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
    }

    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());//碰撞
    }

    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }

    public void repair() {
        System.out.println("Repaired " + this.toString());
    }

    public String toString() {
        return "Car";
    }
}

public class Test {
    public static void main(String[] args) {
        //1. 构造器引用,注意:这个构造器没有参数
        final Car car = Car.create(Car::new);
        //与 final Car car = new Car(); 等价
        final List<Car> cars = Arrays.asList(car);

        //2. 静态方法引用,注意:这个方法接受了一个Car类型的参数
        cars.forEach(Car::collide);

        //3. 特定对象的方法引用,注意:和静态方法引用一样,这个方法接受了一个Car类型的参数
        final Car police = Car.create(Car::new);
        cars.forEach(police::follow);

        //4. 特定类的任意对象的方法引用,注意:这个方法没有定义入参
        cars.forEach(Car::repair);
    }
}
/*
输出
Collided Car
Following the Car
Repaired Car
 */

2. 常见使用情景

a. 打印流:基于静态方法的引用

  • 使用 System.out::println 和 增强 for 快速输出支持迭代的集合:
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String args[]) {
        List names = new ArrayList();
        names.add("Google");
        names.add("Runoob");
        names.add("Taobao");
        names.add("Baidu");
        names.add("Sina");
        names.forEach(System.out::println);
    }
}
/*
输出
Google
Runoob
Taobao
Baidu
Sina
 */

也适用于流的使用:流.forEach(System.out::println);

b. 在泛型中的使用

i. 引用方法

interface SI<String, Integer> {
    Integer S(String string);
}

public class Test {
    public static void main(String[] args) {
        SI<String, Integer> st = Integer::valueOf;//引用Integer类的静态方法valueOf(),传递给st
//        SI<String, Integer> st = new SI<String, Integer>() {
//            @Override
//            public Integer S(String s) {
//                return Integer.valueOf(s);
//            }
//        };
        System.out.println(st.S("100"));//对st.s()使用Integer类的valueOf(),将字符串转换为Integer类型
    }
}
/*
输出
100
 */

ii. 引用构造方法

class Fruit {
    private String name;
    private String color;

    public Fruit(String name, String color) {
        super();
        this.name = name;
        this.color = color;
        System.out.println("name = " + name + ",color = " + color);
    }
}

interface FruitInter<F extends Fruit> {
    F Fruit(String name, String color);//在接口中定义抽象方法Fruit
}

public class Test {
    public static void main(String[] args) {
        FruitInter<Fruit> fi = Fruit::new;//引用Fruit类的构造方法,传递给fi
//        FruitInter<Fruit> fi = new FruitInter<Fruit>() {
//            @Override
//            public Fruit Fruit(String name, String color) {
//                return new Fruit(name, color);
//            }
//        };
        fi.Fruit("apple", "red");//对fi使用Fruit类的构造方法
        //Java编译器自动根据fi.Fruit()方法的签名,选择合适的构造函数
    }
}
/*
输出
name = apple,color = red
 */

3. 与 Lambda 的比较

  • Lambda 表达式:stream.forEach(e-> System.out.println(e));
  • 方法引用:stream.forEach(System.out::println);
  • 可见方法引用是 Lambda 的再进一步简化,但是不建议使用,因为实际操作中可读性差,写代码也不方便;
  • 方法引用可以和 Lambda 表达式配合使用,使得 Java 类的构造方法看起来紧凑而简洁,没有很多复杂的模板代码。