方法引用类型

面试官问:"Java 有哪几种方法引用?"

候选人小秦答:"静态方法引用和实例方法引用。"

面试官追问:"还有呢?"

小秦说:"...好像还有构造器引用?"

面试官追问:"四种方法引用的区别是什么?"

小秦答不上来。

【面试官心理】 方法引用是 Lambda 表达式的简化形式。能说出四种方法引用并能正确使用的候选人,说明对函数式编程有实际经验。

一、四种方法引用 🔴

类型语法示例相当于
静态方法引用ClassName::staticMethodInteger::parseIntx -> Integer.parseInt(x)
实例方法引用(特定对象)object::instanceMethodstr::length() -> str.length()
实例方法引用(任意对象)ClassName::instanceMethodString::lengths -> s.length()
构造器引用ClassName::newArrayList::new() -> new ArrayList()

二、静态方法引用 🔴

// Lambda 形式
Function<String, Integer> parser = s -> Integer.parseInt(s);

// 方法引用形式
Function<String, Integer> parser = Integer::parseInt;

// 使用
parser.apply("123"); // 123

三、实例方法引用(特定对象)🔴

// Lambda 形式
String str = "hello";
Supplier<Integer> len = () -> str.length();

// 方法引用形式
Supplier<Integer> len = str::length;

// 使用
len.get(); // 5

四、实例方法引用(任意对象)🔴

// Lambda 形式
Function<String, Integer> len = s -> s.length();

// 方法引用形式
Function<String, Integer> len = String::length;

// 使用
len.apply("world"); // 5

五、构造器引用 🔴

// Lambda 形式
Supplier<ArrayList<String>> factory = () -> new ArrayList<>();

// 方法引用形式
Supplier<ArrayList<String>> factory = ArrayList::new;

// 带参数的构造器
Function<Integer, ArrayList<String>> factory2 = ArrayList::new;
factory2.apply(10); // new ArrayList<>(10)

// 用于 Stream
Stream<String> stream = Stream.of("a", "b", "c");
Stream<ArrayList<String>> mapped = stream.map(ArrayList::new);

六、方法引用与 Lambda 的选择 🟡

// 方法引用更简洁,可读性更好
// ✅ 优先使用方法引用
list.stream()
    .map(String::toUpperCase)     // 方法引用
    .filter(String::isEmpty)     // 方法引用
    .forEach(System.out::println); // 方法引用

// ✅ Lambda 用于需要计算逻辑时
list.stream()
    .map(s -> s.trim().toUpperCase()) // 需要组合操作
    .filter(s -> s.length() > 3)       // 简单计算

七、常见使用场景 🟡

// 1. Comparator
Comparator<String> c1 = (a, b) -> a.compareToIgnoreCase(b);
Comparator<String> c2 = String::compareToIgnoreCase;

// 2. Function
Function<String, String> trimUpper = String::trim.andThen(String::toUpperCase);

// 3. Consumer
Consumer<String> printer = System.out::println;

// 4. Predicate
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isNotEmpty = isEmpty.negate();

八、追问升级

面试官:"方法引用在编译后会变成什么?"

// 方法引用编译后使用 invokedynamic 指令
// 和 Lambda 类似,运行时通过 LambdaMetafactory 生成

// 静态方法引用:
// String::length 编译后
// invokedynamic # BootstrapMethod
// 相当于生成一个 CallSite 指向 String.length

// 实例方法引用(特定对象):
// str::length 相当于 lambda () -> str.length()
// 捕获了 str 对象