Elimination of function overloading in the Kotlin series and kotlin function Overloading
I. Problems Caused by function Overloading
1. Problems Encountered
Whether in Java or C ++, function Overloading is used to expose interfaces with different parameters, including the number of parameter lists and parameter types, to meet service requirements of different functions, parameter order. However, different adjustments to these parameters will undoubtedly add more functions with the same name, especially for external callers. it is easy to see call errors, especially when the number of parameters is the same, but the parameter types are different, it is easy to make errors.
Take the following example (taking the Thread class as an example ):
public class Thread{ public Thread() { init(null, null, "Thread-" + nextThreadNum(), 0); } public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } public Thread(ThreadGroup group, Runnable target) { init(group, target, "Thread-" + nextThreadNum(), 0); } public Thread(ThreadGroup group, Runnable target, String name) { init(group, target, name, 0); }}
class ThreadTest{ public static void main(String[] args){ Thread thread1 = new Thread(); Thread thread2 = new Thread(new Runnable() { @Override public void run() {//todo } }); Thread thread3 = new Thread(null, new Runnable() { @Override public void run() {//todo } }); Thread thread4 = new Thread(null, new Runnable() { @Override public void run() {//todo } }, "thread_test") }}
2. Solve the Problem
From the above problems, we know that many heavy-load methods will occur in Java. If a call error occurs, we may attribute this problem to being rigorous, but who once thought that a good language can be clearly defined in syntax and reduce some errors in syntax. However, the Kotlin language is superior to Java in terms of syntax, which reduces the possibility of code errors.
To solve the above problem, we can use the function named parameters and default parameters in Kotlin to completely eliminate the function overload problem.
Kotlin solution example:
class Thread(group: ThreadGroup = null, target: Runnable = null, name: String = null) : Runnable{ init(group, target, name, 0) }
fun main(agrs: Array
){ val thread1= Thread() val thread2 = Thread(target = object: Runnable{ override fun run() { //todo } }) val thread3 = Thread(target = object: Runnable{ override fun run() { //todo } }, name = "therad_test") }
Ii. function name parameters in Kotlin
The first problem we need to pay attention to is the readability of functions. However, the appearance of function naming parameters is to solve the readability of functions, and to make callers more readable.
Definition
In Kotlin, when calling a function defined by Kotlin, you can display the names of some parameters, and disrupt the order in which parameters are called, because the parameter name can be used to uniquely locate the specific parameter.
Example of calling in Java
// Define a Java function public static String jow.string (Collection
Collection, String prefix, String seperataor, String postfix) {//...} // call jow.string (collection ,"","","")
In Java, calling the josed string method is actually more confused, especially the three spaces behind it. However, from the call point, it is impossible to know which parameter the joinToString method corresponds, what does each value mean? It is worth trying kotlin.
Example of calling in Kotlin
// Use the default parameter of the function to remove the overload @ JvmOverloadsfun
JoinString (collection: Collection
, Separator: String, prefix: String, postfix: String): String {return collection. jo#string (separator, prefix, postfix)} // call fun main (args: Array
) {Println (joinString (collection = listOf (1, 2, 3, 4), separator = "%", prefix = "<", postfix = "> "))}
In fact, the function overload cannot be solved by naming parameters alone. The naming function only makes it clearer for function calls and the value passed by the caller can correspond to the declared function parameter. To solve the function overload problem, the default value parameter must be used.
3. Default function parameters in Kotlin
When processing the default value parameters, the naming parameters are very useful and generally use the combination of the two to solve the problem of function overloading. In Kotlin, you can specify the default value of a parameter when declaring a function to avoid function overloading. If you use the naming parameters together, you can omit some of the parameters in the middle, or you can specify only the parameters you need in any order you want.
// Use the default parameter of the function to remove the overload @ JvmOverloadsfun
JoinString (collection: Collection
= ListOf (), separator: String = ",", prefix: String = "", postfix: String = ""): String {return collection. jow.string (separator, prefix, postfix)} // call fun main (args: Array
) {// Use the name parameter of the function to improve code readability println (joinString (collection = listOf (1, 2, 3, 4), separator = "% ", prefix = "<", postfix = ">") println (joinString (collection = listOf (1, 2, 3, 4), prefix = "<", postfix = ">") println (joinString (collection = listOf (1, 2, 3, 4), separator = "! ", Prefix =" <") println (joinString (collection = listOf (1, 2, 3, 4), separator = "! ", Postfix ="> ") println (joinString (collection = listOf (1, 2, 3, 4), separator = "! ") Println (joinString (collection = listOf (1, 2, 3, 4), prefix =" <") println (joinString (collection = listOf (1, 2, 3, 4), postfix = ">") println (joinString (collection = listOf (1, 2, 3, 4 )))}
Running result:
<1%2%3%4><1,2,3,4><1!2!3!4][1!2!3!4>[1!2!3!4]<1,2,3,4][1,2,3,4>[1,2,3,4]Process finished with exit code 0
4. @ JvmOverloads annotation solves the problem of Java calling the Kotlin overload Function
Because there is no default value Parameter Concept in Java, when we need to call the default value in Kotlin from Java to reload the function, all the parameter values must be displayed. But this is definitely not what we want. Otherwise, Kotlin will lose the significance of overloading and cannot completely interoperate with Java. Therefore, another solution provided in Kotlin is to use the @ JvmOverloads annotation so that multiple overload methods are automatically generated for Java to call. I can refer to the following example using the Kotlin code:
Kotlin code:
@JvmOverloadsfun
joinString( collection: Collection
= listOf(), separator: String = ",", prefix: String = "", postfix: String = ""): String {return collection.joinToString(separator, prefix, postfix)}
Decompile the code into Java code:
// $FF: synthetic method// $FF: bridge method@JvmOverloads@NotNullpublic static String joinString$default(Collection var0, String var1, String var2, String var3, int var4, Object var5) { if((var4 & 1) != 0) { var0 = (Collection)CollectionsKt.emptyList(); } if((var4 & 2) != 0) { var1 = ","; } if((var4 & 4) != 0) { var2 = ""; } if((var4 & 8) != 0) { var3 = ""; } return joinString(var0, var1, var2, var3);}@JvmOverloads@NotNullpublic static final String joinString(@NotNull Collection collection, @NotNull String separator, @NotNull String prefix) { return joinString$default(collection, separator, prefix, (String)null, 8, (Object)null);}@JvmOverloads@NotNullpublic static final String joinString(@NotNull Collection collection, @NotNull String separator) { return joinString$default(collection, separator, (String)null, (String)null, 12, (Object)null);}@JvmOverloads@NotNullpublic static final String joinString(@NotNull Collection collection) { return joinString$default(collection, (String)null, (String)null, (String)null, 14, (Object)null);}@JvmOverloads@NotNullpublic static final String joinString() { return joinString$default((Collection)null, (String)null, (String)null, (String)null, 15, (Object)null);}
5. Notes
1. When using named parameters in Kotlin functions, you must note that many constructors or common methods are loaded in Java, you cannot use named parameters when calling methods in Java in Kotlin. Whether you are a JDK function or a function in the Android framework, you cannot use named parameters.
2. In Kotlin, the default value of the parameter is compiled into the called function, rather than the called place. Therefore, you need to re-compile the function after changing the default value. We can see from the following decompilation code that Kotlin compiles the default value into the function.
@JvmOverloads@NotNullpublic static String joinString$default(Collection var0, String var1, String var2, String var3, int var4, Object var5) {if((var4 & 1) != 0) { var0 = (Collection)CollectionsKt.emptyList();}if((var4 & 2) != 0) { var1 = ",";}if((var4 & 4) != 0) { var2 = "";}if((var4 & 8) != 0) { var3 = "";}return joinString(var0, var1, var2, var3);}