Generics and Boxing and Unboxing in Java

Everyone knows about boxing and unboxing of generics and primitives.

I'll just say it briefly.

    1. Generics is a new feature of JDK1.5. Its essence is the application of parameterized types, that is to say, the data type to be operated is specified as a parameter. Such parameters can be used in the creation of classes, interfaces, and methods, called generic classes, generic interfaces, and generic methods, respectively.

    The generic type in Java only exists in the program source code, and in the compiled bytecode file, it has been replaced with the original primitive type, and the coercion is inserted in the corresponding place. Therefore, for the Java language at runtime, ArrayList<Integer> and ArrayList<String> are the same class.

    Let's look at a simple example of Java generics.

public static void main(String[] args) {
    Map<String,String> map = new HashMap<String,String>();
map.put("hello","111");
map.put("how are you?","222");
System.out.println(map.get("hello"));
System.out.println(map.get("how are you?"));
}
    
    
    
    

    Compile this code into a Class file, and then decompile it with a bytecode decompilation tool, you will find that the generics are gone

public static void main(String[] args) {
    Map map = new HashMap();
map.put("hello","111");
map.put("how are you?","222");
System.out.println(map.get("hello"));
System.out.println(map.get("how are you?"));
}
    
    
    
    

    This is the erasure of generics at compile time. Generic erasure is only valid at compile time. During the compilation process, after the generic result is correctly checked, the relevant information of the generic is erased, and the method of type checking and type conversion is added at the boundary of the object entering and leaving the method.

   I believe that after reading the above content, you will know the output of the following code.

public static void main(String[] args) {
    Class c1 = new ArrayList<Integer>().getClass();
    Class c2 = new ArrayList<String>().getClass();
    System.out.println(c1==c2);
}

    That's right, it's true. Because only the ArrayList class is generated at compile time, and its Class file must have only one, so it returns true.

    Of course, generic erasure also has shortcomings, such as when generics encounter overloading

public void f(List<String> list){
    System.out.println(list);
}

public void f(List<Integer> list){
    System.out.println(list);
}
    Such code cannot be compiled, because after the generics are erased at compile time, their parameters are all ArrayLists, resulting in the same parameter signatures of the two methods, which cannot resolve the ambiguity.

    2. Automatic packing and unpacking

        What is boxing and unboxing?

            Everyone is familiar with basic type data and wrapper type data.

            Automatic boxing and unboxing are provided in JavaSE 1.5. For example, if we want to create an Integer object with a value of 10, we can do this

            Integer i = 10;

            This is autoboxing, in which an Integer object is automatically created based on the value.

            And int j = i, is automatic unboxing, which is to convert the packaging type to the basic data type.

        Implementation of boxing and unboxing

            see a piece of code

            

public static void main(String[] args) {
    Integer i = 10;
    int j = i;
    System.out.println(j);
}
                after decompiling    


        It can be seen that the Integer.valueOf method is used when assigning a value to the object i, and the Integer.intValue method is used when assigning a value to the variable j.

    There are several pits to pay attention to in the process of packing, for example, you can see in the following code

public static void main(String[] args) {
    Integer i = 100;
    Integer j = 100;
    Integer m = 200;
    Integer n = 200;
    System.out.println(i==j);
    System.out.println(m==n);
}
      The output is true and false, why, we can enter the source code to see

        

    It has a buffer pool between -128 and 127. The number between this does not create a new Integer object directly, but takes it directly from the buffer pool. So they are the same reference, and both return true when comparing with ==, but the other than these numbers is the newly created Integer object, which cannot be the same.

    But Double is different, look at the code

public static void main(String[] args) {
    Double i = 100.0;
    Double j = 100.0;
    Double m = 200.0;
    Double n = 200.0;
    System.out.println(i==j);
    System.out.println(m==n);
}

    它的输出却为两个false。

    还有你能说出Integer i = new Integer(x)和Integer i = x的区别吗?

        第一种不会触发自动装箱,而第二种会触发自动装箱

        第二种在一般情况下的执行效率和空间占用效率比第一种优

    最后再出一个题考考吧 

public static void main(String[] args) {
    Integer a =1;
    Integer b =2;
    Integer c = 3;
    Integer d = 3;
    Integer e = 321;
    Integer f = 321;
    Long g = 3L;
    System.out.println(c==d);
    System.out.println(e==f);
    System.out.println(c==(a+b));
    System.out.println(c.equals(a+b));
    System.out.println(g==(a+b));
    System.out.println(g.equals(a+b));
}

        第一个和第二个没什么说的,第三个用到了关系操作符+,所以触发了自动拆箱,因此比较的是值的大小,返回true;

        第四个用到了操作符+和equals,所以先拆箱后装箱,比较的也是值的大小,所以返回true;第五个用到了操作符+,进行

        自动拆箱后,比较的是值本身,返回true。最后一个用到了操作符+和equals方法,先拆箱后装箱,不过拆箱的时候用的是intValue方法,返回为int,装箱之后也是Integer,而Long的equals方法只能和Long进行比较,其余都返回false。

        

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325656233&siteId=291194637