JavaRush /Java Blog /Random EN /Wrappers, unpacking and packaging

Wrappers, unpacking and packaging

Published in the Random EN group
Hello! You are already quite familiar with primitive types and have done a lot of work with them. Wrappers, unpacking and packing - 1Primitives in programming, and in Java in particular, have many advantages: they take up little memory, thereby increasing the efficiency of the program, and are clearly divided into ranges of values. However, in the process of learning Java, we have repeatedly repeated, like a mantra - “ in Java, everything is an object ”. But primitives are a direct refutation of these words. They are not objects. It turns out that the principle "everything is an object" is false? Not really. In Java, each primitive type has its own twin brother, the wrapper class ( Wrapper). What is a wrapper? A wrapper is a special class that stores the value of a primitive inside. But since it is a class, it can create its own instances. They will store the required values ​​of the primitives inside, while they will be real objects. The names of the wrapper classes are very similar to the names of the corresponding primitives, or completely coincide with them. Therefore, it will be very easy to remember them.
Wrapper Classes for Primitive Data Types
Primitive Data Types Wrapper Classes
int Integer
short short
long Long
byte bytes
float float
double Double
char character
boolean Boolean
Wrapper class objects are created just like any other:
public static void main(String[] args) {

   Integer i = new Integer(682);

   Double d = new Double(2.33);

   Boolean b = new Boolean(false);
}
Wrapper classes allow you to level out the disadvantages that primitive types have. The most obvious of these is that primitives do not have methods . For example, they don't have a method toString(), so you can't, for example, convert a number intto a string. But with a wrapper class Integer- easily.
public static void main(String[] args) {

   Integer i = new Integer(432);

   String s = i.toString();
}
There will be difficulties with the reverse transformation. Let's say we have a string about which we know for sure that it contains a number. Nevertheless, in the case of a primitive type, intwe cannot get this number from the string and turn it into a number. But thanks to wrapper classes, we have such an opportunity.
public static void main(String[] args) {

   String s = "1166628";

   Integer i = Integer.parseInt(s);

   System.out.println(i);
}
Output: 1166628 We successfully got a number from a string and assigned it to a reference variable Integer i. By the way, about links. You already know that parameters are passed to methods in different ways: primitives are passed by value, while objects are passed by reference. You can use this knowledge when creating your methods: if your method works, for example, with fractional numbers, but you need the logic of passing by reference, you can pass parameters to the method instead Double/Floatof double/float. In addition, in addition to methods, wrapper classes have static fields that are very convenient to use. For example, imagine that you are now faced with the task of displaying the maximum possible number in the console int, and then the minimum possible. The task seems to be elementary, but all the same - you can hardly do it without Google. And wrapper classes easily allow you to solve such “everyday tasks”:
public class Main {
   public static void main(String[] args) {

       System.out.println(Integer.MAX_VALUE);
       System.out.println(Integer.MIN_VALUE);
   }
}
Such fields allow you not to be distracted from performing more serious tasks. Not to mention the fact that in the process of printing the number 2147483647 (this is just MAX_VALUE) it is not surprising to make a typo :) In addition, in one of the previous lectures, we already paid attention to the fact that objects of wrapper classes are immutable (Immutable) .
public static void main(String[] args) {

   Integer a = new Integer(0);
   Integer b = new Integer(0);

   b = a;
   a = 1;
   System.out.println(b);
}
Output: 0 The object that was originally pointed to by the reference аhas not changed its state, otherwise the value bwould have changed too. As in the case withString, instead of changing the state of the wrapper object, an entirely new object is created in memory. Why did the creators of Java ultimately decide to leave primitive types in the language? Since everything should be an object, and we already have wrapper classes that can express everything that primitives express, why not just leave them in the language at all, and remove the primitives? The answer is simple - performance. Primitive types are called primitive because they lack many of the "heavyweight" features of objects. Yes, an object has many convenience methods, but you don't always need them. Sometimes you just want the number 33, or 2.62, or the value true/ false. In situations where all the advantages of objects are irrelevant and not needed for the program to work, primitives will do the job much better.

Auto-packing / auto-unpacking

One of the features of primitives and their wrapper classes in Java is autoboxing / autounboxing (Autoboxing / Autounboxing) Wrappers, unpacking and packing - 2 Let's deal with this concept. As you and I already learned earlier, Java is an object-oriented language. This means that all programs written in Java are made up of objects. Primitives are not objects. But at the same time, a wrapper class variable can be assigned a value of a primitive type. This process is called autoboxing . Similarly, a variable of a primitive type can be assigned an object of the wrapper class. This process is called autounboxing . For example:
public class Main {
   public static void main(String[] args) {
       int x = 7;
       Integer y = 111;
       x = y; // auto unpacking
       y = x * 123; // autopacking
   }
}
On line 5, we assign the value of y to the primitive x, which is an object of the wrapper class Integer. As you can see, no additional steps are needed for this: the compiler knows what intand Integer, in fact, the same thing . This is what auto-unpacking is. The same goes for autoboxing on line 6: the object y is easily assigned the value of primitives (x*123). This is an example of autopackaging. That is why the word "auto" is added: to assign primitive references to objects of their wrapper classes (and vice versa), you do not need to do anything, everything happens automatically . Convenient, right? :) Another very great convenience of auto-packing / auto-unpacking is manifested in the work of methods. The fact is that method parameters are also subject to autopacking and auto-unpacking.. And, for example, if one of them takes two objects as input Integer, we can easily pass ordinary primitives there int!
public class Main {
   public static void main(String[] args) {

       printNumber(7);//regular int, even without a variable
   }

   public static void printNumber(Integer i) {
       System.out.println("You entered a number" + i);
   }
}
Conclusion: You entered the number 7. It works the same way and vice versa:
public class Main {
   public static void main(String[] args) {

       printNumber(new Integer(632));
   }

   public static void printNumber(int i) {
       System.out.println("You entered a number" + i);
   }
}
An important point to keep in mind: autoboxing and unboxing doesn't work for arrays !
public class Main {
   public static void main(String[] args) {

       int[] i = {1,2,3,4,5};

       printArray(i);//error, won't compile!
   }

   public static void printArray(Integer[] arr) {
       System.out.println(Arrays.toString(arr));
   }
}
Attempting to pass an array of primitives to a method that takes an array of objects as input will cause a compilation error. Finally, let's once again briefly compare primitives and wrappers Primitives:
  • have a performance advantage
Wrappers:
  • Allows not to violate the principle “everything is an object”, so that numbers, symbols and boolean true/false values ​​do not fall out of this concept
  • Extend the ability to work with these values ​​by providing convenient methods and fields
  • Necessary when a method can work exclusively with objects
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION