📜 ⬆️ ⬇️

Java Challengers # 1: Overloading Methods in JVM

Java Challengers # 1: Overloading Methods in JVM


Good day to all.


We have already launched another stream of the Java Developer course, but we still have some materials that we would like to share with you.


Welcome to the Java Challengers series! This series of articles focuses on the features of Java programming. Their development is your way to becoming a highly qualified Java programmer.


Mastering the techniques covered in this series of articles requires some effort, but they will make a big difference in your everyday experience as a java developer. Avoiding errors is easier when you know how to properly apply basic Java programming techniques and track errors much easier when you know exactly what is happening in your java code.


Are you ready to start mastering the basic concepts of Java programming? Then let's start with our first task!


widening-boxing-varargs


Term "Method Overload"

About the term overload, developers tend to think that this is about rebooting the system, but it is not. In programming, method overloading means using the same method name with different parameters.

What is method overloading?


Method overloading is a programming technique that allows a developer to use the same name for methods with different parameters in the same class. In this case, we say that the method is overloaded.


Listing 1 shows methods with different parameters that differ in number, type, and order.


Listing 1. Three options for overloading methods.


//   public class Calculator { void calculate(int number1, int number2) { } void calculate(int number1, int number2, int number3) { } } //   public class Calculator { void calculate(int number1, int number2) { } void calculate(double number1, double number2) { } } //   public class Calculator { void calculate(double number1, int number2) { } void calculate(int number1, double number2) { } } 

Method Overloading and Primitive Types


In Listing 1, you saw the primitive types int and double . Let's digress for a minute and recall the primitive types in Java.


Table 1. Primitive types in Java


Type ofRangeDefault valueThe sizeLiteral examples
booleantrue or falsefalse1 bittrue false
byte-128 ... 12708 bit1, -90, -128
charUnicode character or from 0 to 65 536\ u000016 bits'a', '\ u0031', '\ 201', '\ n', 4
short-32,768 ... 32,767016 bits1, 3, 720, 22,000
int-2 147 483 648 ... 2 147 483 647032 bits-2, -1, 0, 1, 9
long-9 223 372 036 854 775 808 to 9 223 372 036 854 775 807064 bit-4000L, -900L, 10L, 700L
float3.40282347 x 1038, 1.40239846 x 10-450.032 bits1.67e200f, -1.57e-207f, .9f, 10.4F
double1.7976931348623157 x 10308, 4.9406564584124654 x 10-3240.064 bit1.e700d, -123457e, 37e1d

Why should I use method overloading?


Using overload makes your code cleaner and easier to read, and also helps to avoid errors in the program.


As opposed to Listing 1, imagine a program where you will have many methods of calculate() with names similar to calculate1 , calculate2 , calculate3 ... not good, right? Overloading the calculate() method allows you to use the same name and change only what is needed - the parameters. It is also very easy to find overloaded methods, since they are grouped in code.


What overload is not


Remember that changing a variable name is not an overload. The following code will not compile:


 public class Calculator { void calculate(int firstNumber, int secondNumber){} void calculate(int secondNumber, int thirdNumber){} } 

You also cannot overload the method by changing the return value in the method signature. This code also does not compile:


 public class Calculator { double calculate(int number1, int number2){return 0.0;} long calculate(int number1, int number2){return 0;} } 

Constructor overload


You can overload the constructor in the same way as the method:


 public class Calculator { private int number1; private int number2; public Calculator(int number1) { this.number1 = number1; } public Calculator(int number1, int number2) { this.number1 = number1; this.number2 = number2; } } 

Solve the problem of overloading methods


Are you ready for the first test? Let's find out!


Start by carefully studying the following code.


Listing 2. Difficult task overloading methods


 public class AdvancedOverloadingChallenge3 { static String x = ""; public static void main(String... doYourBest) { executeAction(1); executeAction(1.0); executeAction(Double.valueOf("5")); executeAction(1L); System.out.println(x); } static void executeAction(int ... var) {x += "a"; } static void executeAction(Integer var) {x += "b"; } static void executeAction(Object var) {x += "c"; } static void executeAction(short var) {x += "d"; } static void executeAction(float var) {x += "e"; } static void executeAction(double var) {x += "f"; } } 

Good. You have studied the code. What will be the conclusion?


  1. befe
  2. bfce
  3. efce
  4. aecf

The correct answer is given at the end of the article.


What happened now? How JVM Compiles Overloaded Methods


To understand what happened in Listing 2, you need to know a few things about how the JVM compiles the overloaded methods.


First of all, the JVM is reasonably lazy: it will always make the least effort to implement the method. Thus, when you think about how the JVM handles overload, keep in mind three important features of the compiler:


  1. Expansion (widening)
  2. Packaging (autoboxing and unboxing)
  3. Variable Length Arguments (varargs)

If you have never encountered these techniques, then a few examples should help you understand them. Note that the JVM performs them in the order in which they are listed.


Here is an example of the extension:


 int primitiveIntNumber = 5; double primitiveDoubleNumber = primitiveIntNumber ; 

This is the extension order of primitive types:


Expansion order of primitive types


( Note of the translator - In JLS, the primitive extension is described with large variations, for example, long can be expanded in float or in double. )


Example of autopacking:


 int primitiveIntNumber = 7; Integer wrapperIntegerNumber = primitiveIntNumber; 

Notice what happens behind the scenes when compiling code:


 Integer wrapperIntegerNumber = Integer.valueOf(primitiveIntNumber); 

Here is an example of unpacking:


 Integer wrapperIntegerNumber = 7; int primitiveIntNumber= wrapperIntegerNumber; 

This is what happens behind the scenes when compiling this code:


 int primitiveIntNumber = wrapperIntegerNumber.intValue(); 

And here is an example of a method with variable length arguments. Note that variable length methods are always the last to execute.


 execute(int... numbers){} 

What are variable length arguments?


Variable length arguments are simply an array of values, given by three dots (...). We can pass as many int numbers as necessary to this method.


For example:


 execute(1,3,4,6,7,8,8,6,4,6,88...); //  ... 

Variable-length arguments (varargs) are very convenient in that values ​​can be passed directly to a method. If we used arrays, we would have to create an array instance with values.


Expansion: a practical example


When we pass the number 1 directly to the executeAction() method, the JVM automatically interprets it as an int . That is why this number will not be passed to the executeAction(short var) method.


Similarly, if we pass the number 1.0 JVM automatically recognizes that it is double.


Of course, the number 1.0 can also be a float , but the type of such literals is predetermined. Therefore, in Listing 2, the executeAction(double var) method executeAction(double var) is executed.


When we use the Double wrapper, there are two options: either the number can be decompressed into a primitive type, or it can be expanded in Object . (Remember that every class in Java extends the Object class.) In this case, the JVM chooses an extension of type Double in Object , because it requires less effort than unpacking.


Last we pass 1L and since, we have specified the type - this is long .


Common Overload Errors


By now you have probably realized that with the overloading of methods everything can be confusing, so let's look at a few problems you are likely to encounter.


Autoboxing with wrappers


Java is a strongly typed programming language and, when we use autopacking with wrappers, there are a few things we need to consider. First, the following code does not compile:


 int primitiveIntNumber = 7; Double wrapperNumber = primitiveIntNumber; 

Autopack will only work with double type because when you compile the code, it will be equivalent to this:


 Double number = Double.valueOf(primitiveIntNumber); 

This code will compile. The first int will be expanded to double and then packed in Double . But when autopacking there is no type expansion and the Double.valueof constructor expects a double , not an int . In this case, autopacking will work if we do an explicit type conversion, for example:


 Double wrapperNumber = (double) primitiveIntNumber; 

Remember that the Integer cannot be Long and Float and cannot be Double . There is no inheritance. Each of these types ( Integer , Long , Float , and Double ) is Number and Object .


If in doubt, just remember that wrappers numbers can be expanded to Number or Object . (There is a lot more that can be said about wrappers, but let's leave it for another article.)


Literals of numbers in the code


When we do not specify a literal number type, the JVM will calculate the type for us. If we directly use the number 1 in the code, the JVM will create it as an int . If we try to pass 1 directly to the method that short accepts, it will not compile.


For example:


 class Calculator { public static void main(String... args) { //      // ,   char, short, byte,  JVM    int calculate(1); } void calculate(short number) {} } 

The same rule will apply when the number 1.0 . Although it may be a float , the JVM will consider it a double .


 class Calculator { public static void main(String... args) { //      // ,   float,  JVM    double calculate(1.0); } void calculate(float number) {} } 

Another common mistake is to assume that Double or any other wrapper is better suited for the method that receives a double .


The fact is that the JVM requires less effort to expand the Double wrapper in Object instead of unpacking it into the primitive type double .


To summarize, when used directly in the java-code, 1 will be int and 1.0 will be double . Expansion is the easiest way to accomplish, then comes packaging or unpacking and the last operation will always be variable length methods.


Like a curious fact. Did you know that the type char takes numbers?


 char anyChar = 127; // ,  ,    

What you need to remember about overloading


Overloading is a very powerful technique for when you need the same method name with different parameters. This is a useful technique because using the correct names makes the code easier to read. Instead of duplicating the name of the method and adding clutter to your code, you can simply overload it.


This allows you to keep the code clean and easy to read, and also reduces the risk that duplicate methods will break part of the system.


What should be borne in mind: in case of overloading, the JVM will make the least effort possible.


Here is the order of the laziest way to execute:



What should be considered: difficult situations arise when declaring numbers directly: 1 will be int and 1.0 will be double .


Also remember that you can declare these types explicitly using the syntax 1F or 1f for float and 1D or 1d for double .


This concludes the role of JVM in method overloading. It is important to understand that the JVM is inherently lazy, and will always follow the most lazy path.


Answer


The answer to Listing 2 is Option 3. efce.


Learn more about method overloading in Java.



Introduction to classes and objects for absolute beginners, including small sections on methods and method overloading.



Learn more about why it is important that Java is a strongly typed language and learn Java primitive types.



Learn the limitations and disadvantages of overloading methods, as well as ways to eliminate them by using custom types and parameter objects.


')

Source: https://habr.com/ru/post/428307/


All Articles