精华内容
下载资源
问答
  • Java自动装箱和拆箱的实现原理

    千次阅读 2019-10-02 10:02:31
    一、装箱和拆箱 原始类型转换为对象类型就是装箱,反之就是拆箱。 原始类型byte,short,char,int,long,float,double,...自动装箱时编译器调用valueOf将原始类型值转换成对象,同时自动拆箱时,编译器通过调用类似intV...

    一、装箱和拆箱

    原始类型转换为对象类型就是装箱,反之就是拆箱。
    原始类型byte,short,char,int,long,float,double,boolean对应的封装类为Byte,Shor,Character,Integer,Long,Float,Double,Boolean.

    二、源码解读

    自动装箱时编译器调用valueOf将原始类型值转换成对象,同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成原始类型值。
    以Integer的自动装箱为例:

     public static Integer valueOf(int i) {
            //判断i是否在-128和127之间,存在则从IntegerCache中获取包装类的实例,否则new一个新实例
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    
        //使用亨元模式,来减少对象的创建(亨元设计模式大家有必要了解一下,我认为是最简单的设计模式,也许大家经常在项目中使用,不知道他的名字而已)
        private static class IntegerCache {
            static final int low = -128;
            static final int high;
            static final Integer cache[];
    
            //静态方法,类加载的时候进行初始化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() {}
        }
    
    

    Integer i = 40;相当于调用了Integer.valueOf(40)方法:
    首先判断i是否在-128和127之间,如果在,直接从IntegerCache缓存中获取指定数字的包装类;不存在则new出一个新的包装类。
    IntegerCache内部实现了一个Integer的静态常量数组,在类加载的时候,执行static静态代码块进行初始化-128到127之间的Integer对象,存到cache数组中。cache属于常量,存放在Java的方法区中。

    这就解释了以下的结果:

    Integer i = 40;
    Integer j = 40;
    Integer k = 200;
    i == j    为true;
    i == k   为false;
    Integer i4 = new Integer(40);  
    Integer i5 = new Integer(40);  
    Integer i6 = new Integer(0); 
    i4 == i5   为false,因为直接new,地址不同
    i4 == i5+i6  为true,因为涉及到缓存。
    

    Java8种基本类型的自动装箱源码:

     //boolean原生类型自动装箱成Boolean
        public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }
    
        //byte原生类型自动装箱成Byte
        public static Byte valueOf(byte b) {
            final int offset = 128;
            return ByteCache.cache[(int)b + offset];
        }
    
        //byte原生类型自动装箱成Byte
        public static Short valueOf(short s) {
            final int offset = 128;
            int sAsInt = s;
            if (sAsInt >= -128 && sAsInt <= 127) { // must cache
                return ShortCache.cache[sAsInt + offset];
            }
            return new Short(s);
        }
    
        //char原生类型自动装箱成Character
        public static Character valueOf(char c) {
            if (c <= 127) { // must cache
                return CharacterCache.cache[(int)c];
            }
            return new Character(c);
        }
    
        //int原生类型自动装箱成Integer
        public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }
    
        //int原生类型自动装箱成Long
        public static Long valueOf(long l) {
            final int offset = 128;
            if (l >= -128 && l <= 127) { // will cache
                return LongCache.cache[(int)l + offset];
            }
            return new Long(l);
        }
    
        //double原生类型自动装箱成Double
        public static Double valueOf(double d) {
            return new Double(d);
        }
    
        //float原生类型自动装箱成Float
        public static Float valueOf(float f) {
            return new Float(f);
        }
    
    

    通过源码分析,只有double和float没有使用缓存,每次都是new一个新对象。
    使用缓存的策略是因为缓存的这些对象都是经常使用到的,防止每次自动装箱都创建一次对象的实例。

    缓存对象的范围:
    在这里插入图片描述

    展开全文
  • Java 自动装箱和拆箱

    2019-11-23 11:32:52
    拆箱就是自动将包装器类型转换为基本数据类型 Java的类型分为两部分,一个是基本类型(primitive),如int、double等八种基本数据类型;另一个是引用类型(reference type),如String、List等。而每一个基本类型又...

    装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型
    Java的类型分为两部分,一个是基本类型(primitive),如int、double等八种基本数据类型;另一个是引用类型(reference type),如String、List等。而每一个基本类型又各自对应了一个引用类型,称为包装类型(或装箱类型,boxed primitive)
    通过一个例子来理解,每个输出结果我都注释在上方了
    在这里插入图片描述
    如图上的代码,每一个都是包装类型Integer和Long
    第一,二个输出涉及到JVM 常量池(Constant Pool Table)的知识
    这里简要讲一讲常量池相关的知识。
    常量池是运行时常量池(Runtime Constant Pool)一项,而运行时常量池是方法区的一部分,方法区是所有线程共享的数据区。
    常量池用于存放编译期生成的各种字面量和符号引用 。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只能编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法

    回到代码中
    对于byte、short、long、char、boolean对应的包装类都有对应的常量池,这五种包装器类默认创建在-128到127的对象会存放在在缓存中。
    对于两种浮点数没有实现常量池技术。
    c,d的值是3,在常量池的范围内,给Integer赋值一个int类型时,它会调用一个valueOf()的方法,相当于Integer a = Integer.valueOf(1); 所以引用对象是同一个,返回true
    而e,f的值超出了常量池的范围,会new对象,所以是两个对象,返回false

    再看到c == (a + b),g == (a + b)这两个判断
    当在一项操作中混合使用基本类型与包装类型时,包装类型会自动拆箱,在这里就是Integer拆箱成int,Long拆箱成long,所以比较的就是两个值了,值是相等的,所以返回true

    最后看到c.equals(a + b),g.equals(a + b)这一组
    equals()方法不处理数据转型的关系
    这里我猜测是加法进行了拆箱,然后equals恢复到装箱,所以c.equals(a + b)返回true,因为Integer都是同一个引用,而Long类型的引用显然和Integer的引用不一样,所以返回false

    这里再多看一个别人的例子理解常量池
    在这里插入图片描述
    同样把结果注释在上方
    hello,lo是指向date segment的字符串常量,“Hello”,“lo"是储存在date segment的字符串常量
    当"Hel+lo时,JVM内部做字符串连接,然后将连接的结果保存到heap的一块区域(也就是创建了新对象),
    当"Hel”+“lo"时,因为两个都是字符串常量,JVM内部做字符串连接,然后将结果和所有date segment区的字符串常量作比较,如果没有发现相同字符串就将这个连接后的字符串作为常量放在date segment区,如果发现相同的就将引用指向原有的字符串常量
    所以"Hello"和"Hel”+“lo"是同一块date segment区,所以"Hello”==“Hel”+"lo"是true
    因为hel+“lo"是放在heap区的新对象,所以"hello”==hel+"lo"是false
    而最后一个,String.intern(),编译器会将字符串添加到常量池中并返回指向该常量的引用,hello指向的也是常量池,所以返回的是true

    总结一下,包装类的 "=="运算在不遇到算术运算的情况下不会自动拆箱,以及它们equals()方法不处理数据转型的关系,因此不建议这样使用自动装箱与拆箱。

    展开全文
  • java自动装箱和拆箱

    2019-06-12 15:18:25
    https://www.cnblogs.com/wang-yaz/p/8516151.html
    展开全文
  • java是个包装特别好的绅士,其实即便编译器悄悄在私底下干了什么龌龊事儿,我们一般来说也不是很容易看的到。  不过这些问题可以通过看字节码来解决。  代码很简单: Integer x = 5; x++;  且看字节码: ...
  • 本篇文章主要介绍了详解Java 自动装箱拆箱的实现原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • java 自动装箱和拆箱

    2018-04-22 18:28:00
    java 自动装箱和拆箱 Java数据类型 在Java中,数据类型可以分为两大种,Primitive Type(基本类型)Reference Type(引用类型).基本类型的数值不是对象,不能调用toString(),hashCode(),getClass(),equals()等方法....
    1. Java数据类型

    在Java中,数据类型可以分为两大种,Primitive Type(基本类型)和Reference Type(引用类型).基本类型的数值不是对象,不能调用toString(),hashCode(),getClass(),equals()等方法.所以Java提供了针对每种基本类型的包装类型

    index基本类型大小数值范围默认值包装类型
    1boolean--true/falsefalseBoolean
    2byte8bit-27--27-10Byte
    3char16bit\u0000 - \uffff\u0000Character
    4short16bit-2^15 -- 2^15-10Short
    5int32bit-2^31 -- 2^31-10Integer
    6long64bit-2^63 -- 2^63-10Long
    7float32bitIEEE 7540.0fFloat
    8double64bitIEEE 7540.0dDouble
    9void---------Void
    1. Java自动装箱和拆箱定义

      Java 1.5中引入了自动装箱和拆箱机制:

      1. 自动装箱:把基本类型用它们对应的引用类型包装起来,使它们具有对象的特质,可以调用toString()、hashCode()、getClass()、equals()等方法。

        如下:

        Integer a=3;//这是自动装箱

        其实编译器调用的是static Integer valueOf(int i)这个方法,valueOf(int i)返回一个表示指定int值的Integer对象,那么就变成这样:

        Integer a=3; => Integer a=Integer.valueOf(3);

      2. 拆箱:跟自动装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为基本类型的数据。

        如下:

        int i = new Integer(2);//这是拆箱

        编译器内部会调用int intValue()返回该Integer对象的int值

        注意:自动装箱和拆箱是由编译器来完成的,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。

    2. 疑问解答

      5.1. 看IntegerCache的源码可以知道Integer的缓存至少要覆盖[-128, 127]的范围,为什么?

      参见《The Java™Language Specification Java SE 7Edition 5.1.7》Boxing Conversion的描述

      If the valuepbeing boxed is true, false, a byte, or a char inthe range \u0000 to \u007f,or an int or short number between -128 and 127 (inclusive),then let r1and r2 be the results of any two boxing conversions of p. It is always the case thatr1==r2.

      如果被装箱的值为true, false,一个字节,或在range \u0000到\u007f中,或在-128和127之间的整数或短数,那么让r1和r2是p的任何两个装箱转换的结果,它总是r1==r2。

      5.2. 其它基本数据类型对应的包装类型的自动装箱池大小

       Byte,Short,Long对应的是-128~127
       
       Character对应的是0~127
       
       Float和Double没有自动装箱池
      
    3. 总结

      Java使用自动装箱和拆箱机智,节省了常用数值的内存开销和创建对象的开销,提高了效率.通过上面的研究和测试.

      1. Integer和int之间可以进行各种比较;Integer对象将自动拆箱后与int值比较
      2. 两个Integer对象之间也可以用>,<等符号比较大小;两个integer对象拆箱后,再比较大小
      3. 两个Integer对象最好不要用==比较,因为:-128~127范围(一般是这个范围)内是去换村内对象,所以相等,该范围外是两个不同对象引用比较,所以不等.
    展开全文
  • Java自动装箱和拆箱

    2021-12-18 15:13:09
    以下都是Java的基础面试题,相信大家都会有种及眼熟又陌生的感觉、看过可能在短暂的面试...这里通过讲解 int Interger 区别,解答Java自动装箱和拆箱。 自动装箱 ----- 基本类型的值 → 包装类的实例 自动拆箱 ---
  • Java自动装箱拆箱

    2018-04-13 00:49:52
    //自动装箱2、自动拆箱System.out.println(iObj + 12); //自动拆箱3、演示代码package cn.sunft.day01; /** * @author sunft * */ public class AutoBox { /** * @param args */ public static void...
  • JAVA自动装箱和拆箱

    2021-03-08 20:02:55
    例子:// equal比较的是内容,==比较的对象的地址,...其实按照我自己的理解自动装箱就可以简单的理解为将基本数据类型封装为对象类型,来符合java的面向对象;例如用int来举例://声明一个Integer对象Integer num =...
  • 主要给大家介绍了关于Java自动装箱拆箱引起的耗时的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
  • Java自动装箱与自动拆箱(包装类)

    千次阅读 多人点赞 2019-06-15 10:18:39
    包装类的作用: Java 语言中,一切都是对象,但是有例外: 8 个基本数据类型不是对象,因此在很多时候非常不方便。 为此, Java提供为 8 个基本类型提供了对应的包装类: byte ------- Byte short ------ Short ....
  • 一、自动装箱和拆箱 1.自动装箱 JDK5之前,如果要实现一个Integer类型...拆箱和装箱对应,示例如下: Integer i = 1; //此处是装箱 int a = i; //此处是拆箱 简答来说,拆箱就是把封装类型转换为基础数据类型的操作 .

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 41,298
精华内容 16,519
关键字:

java自动装箱和拆箱

java 订阅