Until J2SE1.4, it has been impossible to define methods with variable real parameters in Java programs - because Java requires that the number and types of real parameters (Arguments) and formal parameters must be matched one by one, and the number of formal parameters is fixed when defining the method. Although the same method can be provided with a different number of formal parameters through the overload mechanism, this still cannot achieve the purpose of allowing the real parameter quantity to change arbitrarily.
However, the semantics of some methods require that they must be able to accept variable number of actual parameters - for example, the famous main method needs to be able to accept all command line parameters as actual parameters, and the number of command line parameters cannot be determined in advance.
For this problem, traditionally, the practice of "using an array to wrap the actual parameters to be passed" is generally used to deal with it.
1. Wrap the parameters in an array
The practice of "wrap actual parameters with arrays" can be divided into three steps: first, define an array-type parameter for this method; then when called, generate an array containing all the actual parameters to be passed; finally, pass this array as a real parameter.
This approach can effectively achieve the purpose of "making the method accept variable parameters", but the form when calling is not simple enough.
The Varargs mechanism is provided in J2SE1.5, allowing direct definition of formal parameters that can match multiple real parameters. Thus, a variable number of actual parameters can be passed in a simpler way.
The meaning of Varargs
Generally speaking, "Varargs" means "variablenumberofarguments". Sometimes it is simply called "variablearguments", but because this term does not indicate what is variable, the meaning is a little vague.
2. Define a method with variable real parameters
Just add three consecutive "." (i.e. "...", an ellipsis in the sentence in English) between the "type" and the "parameter name" of a formal parameter, and it can match an uncertain actual parameter. A method with such formal parameters is a method with variable real parameters.
Listing 1: A method with variable real parameters
private static int sumUp(int... values) {}Note that only the last formal parameter can be defined as "can match an uncertain actual parameter". Therefore, there can only be one such formal parameter in a method. In addition, if this method has other formal parameters, put them in the front position.
The compiler will convert the last formal parameter into an array formal parameter in secret and make a mark in the compiled class file to indicate that this is a method with variable real parameters.
Listing 2: Secret form of a method with variable real parameters
private static int sumUp(int[] values) {}Because of such transformations, it is impossible to define a method for this class that is consistent with the converted method signature.
Listing 3: Combinations that will cause compilation errors
private static int sumUp(int... values) {}private static int sumUp(int[] values) {}3. Call a method with variable number of real parameters
As long as the actual parameters to be passed are written one by one to the corresponding position, a method with variable number of real parameters can be called. No other steps are required.
Listing 4: Several parameters can be passed
sumUp(1,3,5,7);
Indirectly, the compiler will convert this calling process into the form of "array wrapped in actual parameters":
Listing 5: Secretly appearing array creation
sumUp(newint[]{1,2,3,4});
In addition, the "uncertain one" mentioned here also includes zero, so such a call is reasonable:
Listing 6: You can also pass zero actual parameters
sumUp();
The effect of this calling method secretly converted by the compiler is equivalent to this:
Listing 7: Zero real arguments correspond to empty arrays
sumUp(newint[]{});
Note that the past is passed at this time, not null. This allows for a unified form to be handled without having to detect which situation it belongs to.
4. Process the actual parameters with variable numbers
The method of processing variable-numbered actual parameters is basically the same as the method of processing array actual parameters. All actual parameters are saved in an array with the same name as the formal parameters. According to actual needs, after reading out the elements in this array, steaming or cooking, you can do whatever you want.
Listing 8: Processing the received arguments
private static int sumUp(int... values) { int sum = 0; for (int i = 0; i < values.length; i++) { sum += values[i]; } return sum;}5. Forward the variable number of parameters
Sometimes, after accepting a set of variable number parameters, they have to be passed to another variable number method. Because the number of actual parameters received during encoding cannot be known, the practice of "writing them one by one to the location where they should appear" is not feasible. However, this does not mean that this is an unfinishable task, because there is another way to call a method with variable real parameters.
In the eyes of the J2SE1.5 compiler, the method with variable real parameters is a special case of the method with an array of formal parameters at the end. Therefore, put the entire set of actual parameters to be passed into an array in advance, and then pass this array as the last actual parameter to a method with variable number of real parameters, which will not cause any errors. With this feature, forwarding can be completed smoothly.
Listing 9: Forwarding the received actual parameters
public class PrintfSample { public static void main(String[] args) { printOut("Pi:%f E:%f/n", Math.PI, Math.E); } private static void printOut(String format, Object... args) { System.out.printf(format, args); }}6. Is it an array? Not an array?
Although behind the scenes, the compiler will convert formal parameters that can match uncertain real parameters into array formal parameters; and it can also use an array to wrap the actual parameters and then pass them to a method with variable number of real parameters; however, this does not mean that there is no difference between "the formal parameters that can match uncertain real parameters" and "array formal parameters".
An obvious difference is that if you call a method whose last formal parameter is an array formal parameter in the form of a method with variable number of real parameters, it will only lead to a "cannotbeappliedto" compilation error.
Listing 10: A compilation error for "cannotbeappliedto"
private static void testOverloading(int[] i) {System.out.println("A");}public static void main(String[] args) {testOverloading(1, 2, 3);//Compilation error}For this reason, this concise call method cannot be directly adopted when calling methods that only support wrapping actual parameters with arrays (for example, those left over from third-party library designs for J2SE1.5).
If you cannot modify the original class and add a variable version of the number of parameters to the method to be called, and you want to adopt this concise calling method, you can use the reconstruction methods of "introduceForeignMethod" and "introduceLocalExtension" to approximate the purpose.
7. When a variable number of arguments encounters a generic
A new "generic" mechanism has been added to J2SE1.5, which can parameterize a type under certain conditions. For example, when writing a class, the type of a method's formal parameters can be represented by an identifier (such as T). As for what type this identifier represents, it is specified when generating an instance of this class. This mechanism can be used to provide more complete code reuse and stricter compile-time type checking.
However, the generic mechanism cannot be used with variable numbers of formal parameters. If a formal parameter type that matches an uncertain argument is represented by an identifier, the compiler will give a "genericarraycreation" error.
Listing 11: When Varargs meets generics
private static void testVarargs(T... args) {//Compilation error}The reason for this phenomenon is an inherent constraint of the generic mechanism in J2SE1.5 - an instance of this type cannot be created with the type represented by an identifier. Before the Java version supporting without this constraint appeared, there was basically no good solution to this problem.
However, the traditional "wrap with arrays" practice is not subject to this constraint.
Listing 12: Compilable workarounds
private static void testVarargs(T[] args) { for (int i = 0; i < args.length; i++) { System.out.println(args[i]); }}8. Selection issues in overloading
Java supports "overloading" mechanisms, allowing many different methods in the same class to have only lists of formal parameters. Then, the compiler selects which method to execute based on the actual parameters at the time of call.
Traditional choices are basically based on the principle of "special people are preferred". The speciality of a method depends on the number of conditions that need to be met in order for it to run smoothly. The more conditions you need, the more special it is.
After the introduction of the Varargs mechanism, this principle still applies, but the issues to be considered are enriched - traditionally, among the various versions of an overloaded method, only those whose morphological parameters and real parameters are exactly the same are eligible for further consideration. However, after the introduction of the Varargs mechanism, it is possible to match both versions, and there is no difference in other aspects, just that one real parameter has a fixed number and the other real parameter has a variable number.
In this case, the determination rule used is that "the version with fixed number of real parameters takes precedence over the version with variable number of real parameters".
Listing 13: Versions with fixed number of real parameters are preferred
If, in the compiler's view, multiple methods have the same priority, it will be stuck in a state where it cannot make a choice about which method to call. In this case, it will generate a compilation error of "referenceto called method name isambiguous" and wait patiently for some modifications to avoid the arrival of the new source code that is confusing.
After the introduction of the Varargs mechanism, this situation that may lead to confusion has increased a little more. For example, there may be two versions that can match, which is exactly the same in other aspects, and both conflicts with variable numbers of real parameters occur.
public class OverloadingSampleA {public static void main(String[] args) {testOverloading(1);//Print out AtestOverloading(1, 2);//Print out BtestOverloading(1, 2, 3);//Print out C}private static void testOverloading(int i) {System.out.println("A");}private static void testOverloading(int i, int j) {System.out.println("B");}private static void testOverloading(int i, int... more) {System.out.println("C");}}If, in the compiler's view, multiple methods have the same priority, it will be stuck in a state where it cannot make a choice about which method to call. In this case, it will generate a compilation error of "referenceto called method name isambiguous" and wait patiently for some modifications to avoid the arrival of the new source code that is confusing.
After the introduction of the Varargs mechanism, this situation that may lead to confusion has increased a little more. For example, there may be two versions that can match, which is exactly the same in other aspects, and both conflicts with variable numbers of real parameters occur.
Listing 14: No matter what, it's hard for the compiler to be
public class OverloadingSampleB {public static void main(String[] args) {testOverloading(1, 2, 3);//Compilation error}private static void testOverloading(Object... args) {}}In addition, because there is the "Autoboxing/Auto-Unboxing" mechanism in J2SE1.5, it is possible that both versions can match, and the number of real parameters is variable, and the other aspects are exactly the same. It is just that one acceptable real parameter is the basic type, while the other acceptable real parameter is the conflict between the package class.
Listing 15: New Issues from Autoboxing/Auto-Unboxing
public class OverloadingSampleC {public static void main(String[] args) {/* Compilation error*/testOverloading(1, 2);/* Or compile error*/testOverloading(new Integer(1), new Integer(2));}private static void testOverloading(int... args) {}private static void testOverloading(Integer... args) {}}9. Summary
Compared with the "wrapped with arrays" method, the real method with variable real parameters is simpler and has clearer meanings when calling. However, this mechanism also has its own limitations and is not a perfect solution.
The above is all the detailed explanation of variable length parameter code in Java, I hope it will be helpful to everyone. Interested friends can continue to refer to this site:
Detailed explanation of implicit parameters and display parameter instances in Java
Java programming implementation of quick sorting and optimization code detailed explanation
Java Encryption Decryption and Digital Signature Complete Code Example
If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!