• java自动装箱、拆箱、循环遍历与自动装箱的陷阱


    java自动装箱、拆箱、循环遍历与自动装箱的陷阱

    1. 自动装箱、拆箱、循环遍历

    • 编译之前的代码
    package com.zhu.part10;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * 自动装箱,自动拆箱,循环遍历
     * @author xiaozhu
     * @date 2022年07月18日 23:20
     */
    public class Demo10_11 {
    
        public static void main(String[] args) {
    
    
            //自动装箱
           List<Integer> list = Arrays.asList(1, 2, 3, 4);
    
           int sum = 0;
    
           //自动拆箱,循环遍历
           for (int i : list) {
                sum += i;
           }
            System.out.println(sum);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • jdk8 编译之后的class文件中的代码
    //
    // Source code recreated from a .class file by IntelliJ IDEA
    // (powered by Fernflower decompiler)
    //
    
    package com.zhu.part10;
    
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.List;
    
    public class Demo10_11 {
        public Demo10_11() {
        }
    
        public static void main(String[] args) {
            List<Integer> list = Arrays.asList(1, 2, 3, 4);
            int sum = 0;
    
            int i;
            for(Iterator var3 = list.iterator(); var3.hasNext(); sum += i) {
                i = (Integer)var3.next();
            }
    
            System.out.println(sum);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 《深入理解java虚拟机》作者环境编译后的class文件
    package com.zhu.part10;
    
    import java.util.Arrays;
    import java.util.Iterator;
    import java.util.List;
    
    /**
     * 自动装箱、拆箱与遍历循环之后
     * @author xiaozhu
     * @date 2022年07月18日 23:24                          $
     */
    public class Demo10_12 {
        public static void main(String[] args) {
    
    
            //转化成了对应的包装和还原方法:Integer.valueOf(),Integer.intValue()
            //变长参数,调用的时候使用了一个数组类型的参数
            List list = Arrays.asList(new Integer[] {
               Integer.valueOf(1),
               Integer.valueOf(2),
               Integer.valueOf(3),
               Integer.valueOf(4)
            });
    
            int sum = 0;
    
            //遍历循环则是还原成了迭代器去实现
            for (Iterator localIterator = list.iterator(); localIterator.hasNext();) {
                sum += ((Integer)localIterator.next()).intValue();
            }
            System.out.println(sum);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    在泛型中,自动装箱、拆箱转化成对应的包装和还原方法,比如自动装箱Integer.valueOf() 和自动拆箱 Integer.intValue()

    我们可以重点查看自动装箱方法的源码,Integer.valueOf()

      
      //这个源码是个坑
      public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
      }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    image-20220720122106667

    image-20220720122138468

    由此我们可以得到这样一个结论:Integer的默认缓存范围为-128到127,在自动装箱的时候,如果数字范围在-128到127,则直接返回缓存中已有的对象,不在这个范围之内则new一个新的对象。

    这也就以下代码打印false的原因

    Integer e = 321;
    Integer f = 321;
    System.out.println(e == f);
    
    //打印false
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 自动拆箱的陷阱

    package com.zhu.part10;
    
    /**
     * 自动装箱的陷阱
     * @author xiaozhu
     * @date 2022年07月20日 10:43                          $
     */
    public class Demo10_13 {
        public static void main(String[] args) {
    
            //Integer 是 int的包装类
            //Long 是 long的包装类
    
    
            Integer a = 1;
            Integer b = 2;
            Integer c = 3;
            Integer d = 3;
            Integer e = 321;
            Integer f = 321;
            Long g = 3L;
    
    
            //1、包装类的 "==" 运算在不遇到算数运算的时候不会自动拆箱,以及它们的equals()方法不处理数据类型转换
            System.out.println(c == d); //true
    
            //2、安照1中的思路应该就是true,但是此处也是一个小坑,上文中有详细解释
            System.out.println(e == f); //false
    
            //3、true 自动拆箱后的值和类型相等
            System.out.println(c == (a + b)); 
    
            //4、true 值和类型都相等
            System.out.println(c.equals(a + b));
    
            //包装类的 "==" 运算在不遇到算数运算的时候不会自动拆箱
            //5、a + b是算数运算 ,所以包装类拆箱,拆箱后两边数值相等,返回true
            System.out.println(g == (a + b));//true
    
            //6、包装类的equals()方法不处理数据类型转换,g和a+b的类型不同,所以返回false
            System.out.println(g.equals(a + b));
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    一些方法技巧:

    • 我们可以在idea中查看java文件编译之后的class文件

    image-20220720122204414

    • 遇到问题我们可以通过查看源码的方式进一步发现和理解问题的所在

    参考书籍:《深入理解java虚拟机》

    如有错误和冒犯,欢迎指正。

  • 相关阅读:
    供应原厂电流继电器 - HBDLX-21/3 整定电流范围0.1-1.09A AC220V
    整理了27个Python人工智能库,建议收藏!
    App爬虫之强大的Airtest的操作总结
    unity UDP 通信
    【SnowFlake】雪花算法(Java版本)
    Unity鼠标光标使用学习
    又发现一款独立清理神器,界面清爽,功能强大,没有广告!
    git能pink成功,为什么一直克隆超时啊
    【设计模式】Java设计模式 - 单例模式
    go开发调试之Delve的使用
  • 原文地址:https://blog.csdn.net/qq_54650406/article/details/125889765