zoukankan      html  css  js  c++  java
  • 知识归纳笔记(二):考查自动装箱与拆箱

    自动装箱与拆箱

    最近遇到一个面试题,是关于自动装箱和拆箱相关的,代码如下所示

    public static void main(String[] args)  {
            
             Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150; 
             System.out.println(f1 == f2); //true
             System.out.println(f3 == f4); //false
        }

    老规矩反编译一下,代码如下:

    public class Test
    {
      public static void main(String[] args)
      {
        Integer f1 = Integer.valueOf(100); Integer f2 = Integer.valueOf(100); Integer f3 = Integer.valueOf(150); Integer f4 = Integer.valueOf(150);
        System.out.println(f1 == f2);
        System.out.println(f3 == f4);
      }

    答题准备:知识点复习

    • 自动装箱
      • 定义:装箱就是自动将基本数据类型转换为包装器类型。
      • 实质:调用Integer.valueOf()
    •  自动拆箱
      • 定义:自动将包装器类型转换为基本数据类型
      • 实质:调用Integer.intValue()

    自动装箱拆箱过程如下代码:

        public static void main(String[] args)  {
            
            //自动装箱
             Integer boxing = 99;
        
             //自定拆箱
             int unpacking = boxing;
               }

    反编译后代码如下:

      public static void main(String[] args)
      {
        Integer boxing = Integer.valueOf(99);
    
        int unpacking = boxing.intValue();
      }

    解题前言:装箱与拆箱类型有很多,我们在这里只以Integer类型举例

    1. 基本类型:byte、short、int、long、float、double、char、boolean
    2. 基本引用类型:Byte、Short、Integer、Long、Float、Double、Character、Boolean

    (1). 看到f1 == f2 我们第一想到的是 f1与f2都是引用类型,比较的是地址,所以得出结论是false。然而看到结果f1 ==f2 是true,就一大堆问号飘过。废话不多说,我们追本溯源研究一下源代码吧,点进Integer.valueOf(100)方法,我们看到如下代码:

        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }

    它会首先判断i的大小:如果 i 大于等于IntegerCache.low与 i 小于等于IntegerCache.high时调用IntegerCache.cache[i + (-IntegerCache.low),否则new Integer(i)对象。要想知道 i 的范围,我们又得研究一下IntegerCache,通过IDEA工具点击进入发现IntegerCache是Integer的内部类,其代码如下所示:

     /**
         * Cache to support the object identity semantics of autoboxing for values between
         * -128 and 127 (inclusive) as required by JLS.
         *
         * The cache is initialized on first usage.  The size of the cache
         * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
         * During VM initialization, java.lang.Integer.IntegerCache.high property
         * may be set and saved in the private system properties in the
         * sun.misc.VM class.
         */
    
        private static class IntegerCache {
            static final int low = -128;
            static final int high;
            static final Integer cache[];
    
            static {
                // high value may be configured by property
                int h = 127;
                String integerCacheHighPropValue =
                    sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                if (integerCacheHighPropValue != null) {
                    try {
                        int i = parseInt(integerCacheHighPropValue);
                        i = Math.max(i, 127);
                        // Maximum array size is Integer.MAX_VALUE
                        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                    } catch( NumberFormatException nfe) {
                        // If the property cannot be parsed into an int, ignore it.
                    }
                }
                high = h;
    
                cache = new Integer[(high - low) + 1];
                int j = low;
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
    
                // range [-128, 127] must be interned (JLS7 5.1.7)
                assert IntegerCache.high >= 127;
            }
    
            private IntegerCache() {}
        }

    查看内部类上面的注释,大致意思是 缓存支持JLS要求的-128和127(含)。缓存在首次使用时会初始化(在常量池中)。缓存的大小可以由{@code-xx:autoboxcachemax=<size>}选项控制。在虚拟机初始化期间,java.lang.Integer.IntegerCache.High属性可以设置并保存在sun.misc.vm类(配置类)。

    看到上述解释以及代码,我们得出结论:当传入某个值大于等于IntegerCache.low(-128)且小于等于IntegerCache.high(默认127)时调用IntegerCache.cache[i + (-IntegerCache.low)(初始化时缓存的[-128, 127] 值),否则new Integer(i)对象。然后回过来看看f1和f2,其值[-128, 127]范围内,并没有重新new一个对象,这就不难得出f1 == f2是 true了。

    (2).同理(一), 我得出150并不在[-128, 127]范围内,所以f3和f4都new一个新对象放在堆中,这就不难得出f3 == f4是 false了。

    总结

    其他封装类类型初始化值范围

    类型 初始化值范围
    Integer [-128,127]
    Byte [-128,127]
    Boolean TRUE,FALSE
    Short [-128,127]
    Long [-128,127]
    Float
    Double
    Character (~,127]

    Integer的JVM简易图

    题内以及题外知识点归纳

    • 引发装箱和拆箱
      • 当两种不同类型用==比较时,包装器类的需要拆箱, 当同种类型用==比较时,会自动拆箱或者装箱
      • equals(Object o) 因为原equals方法中的参数类型是封装类型,所传入的参数类型(a)是原始数据类型,所以会自动对其装箱,反之,会对其进行拆箱
    • 封装类型在首次使用时会将某个范围值缓存初始化(在常量池中),在装箱过程中,如果不在其范围内会重新new一个全新的对象,否则取常量池中的对象
    • 装箱操作会创建对象,频繁的装箱操作会消耗许多内存,影响性能,所以可以避免装箱的时候应该尽量避免。
  • 相关阅读:
    scrapy的自动限速(AutoThrottle)扩展
    js可以控制文件上传的速度吗?
    用DataReader 分页与几种传统的分页方法的比较
    jdbc分页查询
    几种分页方式分析.
    mybatis下的分页,支持所有的数据库
    java 物理分页和逻辑分页
    IBatis的分页研究
    JDBC分页
    用Java实现异构数据库的高效通用分页查询功能
  • 原文地址:https://www.cnblogs.com/kongliuyi/p/11591886.html
Copyright © 2011-2022 走看看