函数签名 Function Signature
函数签名是用来唯一标识一个函数的核心特征集合,你可以把它理解成函数的“身份证”——编译器/编程语言通过这些特征区分不同的函数,核心作用是“识别函数、判断函数是否匹配”。
在 Kotlin/Java 等主流语言中,函数签名的核心组成是:
- 函数名
- 参数列表(参数的数量、类型、顺序)
- (部分场景)返回值类型(Kotlin/Java 中方法重载不看返回值,但函数类型匹配、接口抽象方法匹配会看)
注意:函数签名不包含函数体、参数名、访问修饰符(public/private)、注解等“非核心特征”。
一、先看直观例子(Kotlin)
1. 相同签名的函数(编译器会认为是同一个函数,报错)
// 函数1
fun calculate(a: Int, b: Int): Int {
return a + b
}
// 函数2:仅参数名变了,签名和函数1完全一样 → 编译报错(重复定义)
fun calculate(x: Int, y: Int): Int { // ❌ 重复函数
return x * y
}
// 函数3:仅返回值类型变了,Java 中算同签名,但 Kotlin 函数类型匹配时算不同
fun calculate(a: Int, b: Int): String { // Java 中编译报错,Kotlin 中允许(但重载无意义)
return "${a + b}"
}
2. 不同签名的函数(合法的重载)
// 函数1:参数 (Int, Int)
fun calculate(a: Int, b: Int): Int {
return a + b
}
// 函数2:参数 (Int, Int, Int) → 签名不同(参数数量变了)
fun calculate(a: Int, b: Int, c: Int): Int {
return a + b + c
}
// 函数3:参数 (Int, String) → 签名不同(参数类型/顺序变了)
fun calculate(a: Int, b: String): Int {
return a + b.toInt()
}
二、函数签名的核心应用场景
1. 函数重载(Overload)
只有签名不同的函数才能同名(重载),这是最基础的应用:
// 重载:签名分别是 (Int)、(String)、(Int, Int) → 合法
fun printValue(value: Int) { println("Int: $value") }
fun printValue(value: String) { println("String: $value") }
fun printValue(a: Int, b: Int) { println("Int+Int: ${a+b}") }
2. 函数类型匹配(和你之前问的“函数类型/函数式接口”强相关)
Kotlin 中判断“函数类型是否和函数式接口的抽象方法匹配”,核心就是对比签名:
// 函数式接口:抽象方法签名是 (String) -> Boolean
fun interface Validator {
fun validate(input: String): Boolean
}
// 函数类型:签名 (String) -> Boolean → 和接口抽象方法签名完全匹配 → 可自动转换
val checkLength: (String) -> Boolean = { it.length > 6 }
val validator: Validator = checkLength // ✅ 签名匹配,转换成功
// 函数类型:签名 (Int) -> Boolean → 签名不匹配 → 编译报错
val checkAge: (Int) -> Boolean = { it > 18 }
val validator2: Validator = checkAge // ❌ 类型不匹配
3. 函数式接口的 SAM 转换
SAM 转换能生效的前提是:lambda 的签名和接口抽象方法的签名完全一致:
// 接口抽象方法签名:(Int, Int) -> Int
fun interface Calculator {
fun compute(a: Int, b: Int): Int
}
// lambda 签名:(Int, Int) -> Int → 匹配 → SAM 转换生效
val add = Calculator { a, b -> a + b } // ✅
// lambda 签名:(Int) -> Int → 不匹配 → 编译报错
val double = Calculator { a -> a * 2 } // ❌ 参数数量不匹配
三、补充:Kotlin vs Java 签名规则的小差异
| 规则 | Java | Kotlin |
|---|---|---|
| 返回值是否算签名 | 不算(仅参数列表+函数名) | 函数重载时不算,但函数类型匹配时算 |
| 参数顺序是否算签名 | 算((Int,String)≠(String,Int)) | 算(和 Java 一致) |
| 参数名是否算签名 | 不算 | 不算 |
四、总结
- 核心定义:函数签名是函数的“身份证”,核心包含函数名 + 参数列表(数量/类型/顺序),部分场景包含返回值类型。
- 核心作用:区分不同函数(重载)、判断函数类型/接口方法是否匹配(SAM 转换/函数类型转换)。
- 关键特征:参数名、修饰符、函数体等不算签名,参数类型/数量/顺序是核心。
简单记:看函数“长什么样”,不看“叫什么名字(参数名)”、不看“做什么事(函数体)”,就是函数签名。