精华内容
下载资源
问答
  • JAVA自动拆装箱
    2021-03-14 14:44:03

    1.自动拆装箱是什么?(是什么)

    自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱.

    java中有8中基本的数据类型,这八种基本的数据类型都有对应的封装类型,下面是对应关系:

    int——Integer

    float——Float

    double——Double

    byte——Byte

    long——Long

    char——Character

    boolean——Boolean

    short——Short

    2.java为什么要引入自动装箱和拆箱的功能?(为什么)举个例子:主要是用于java集合中,List list=new ArrayList();

    list集合如果要放整数的话,只能放对象,不能放基本类型,因此需要将整数自动装箱成对象,基本数据类型,如int,float,double,boolean,char,byte,不具备对象的特征,不能调用方法。

    实现原理:javac编译器的语法.

    3.又是怎么实现的呢?(怎么做)

    (举个例子)

    装箱:将基本类型转换成包装类对象int i=10;Integer x=new Integer(i);手动装箱Integer y=10;自动装箱拆箱:将包装类对象转换成基本类型的值Integer j=new Integer(8);int m=j.intValue();//手动拆箱int n=j;//自动拆箱

    看下面这段代码,为什么?(T为true,F为false)

    public class Main {

    public static void main(String[] args) {

    Integer a = 10;

    Integer b = 20;

    Integer c = 30;

    Integer d = 30;

    Integer e = 320;

    Integer f = 320;

    Long g = 30L;

    Long h = 20L;

    System.out.println(c==d);//T

    System.out.println(e==f);//F

    System.out.println(c==(a+b));//T

    System.out.println(c.equals(a+b));//T

    System.out.println(g==(a+b));//

    System.out.println(g.equals(a+b));

    System.out.println(g.equals(a+h));

    }

    }

    解释:

    因为自动装箱,自动调用valueOf方法.

    public static Integer valueOf(int i) {//Integer包装类的

    if (i >= IntegerCache.low && i <= IntegerCache.high)

    return IntegerCache.cache[i + (-IntegerCache.low)];

    return new Integer(i);

    }

    Integer的valueOf方法中一句判断,i >= -128 && i <= IntegerCache.high

    如果数值在-128和127之间,就直接调用IntegerCache类,返回缓存中的数据,自然是同一个对象.

    否则新建一个Integer对象.

    (Double包装类的valueOf方法直接新建一个新对象)

    (Boolean包装类valueOf方法,返回 (b ? TRUE : FALSE),)其他的请自行查看,判断.

    同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成原始类型值,其实就是自动装箱的相反操作.

    4.注意点(弊端):

    容易生成无用对象,因为自动装箱会隐式地创建对象,像前面提到的那样,如果在一个循环体中,会创建无用的中间对象,这样会增加GC压力,拉低程序的性能。所以在写循环时一定要注意代码,避免引入不必要的自动装箱操作.

    更多相关内容
  • 主要介绍了Java三目运算中隐藏的自动拆装箱,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
  • 主要为大家详细介绍了Java自动拆装箱的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Java中的自动拆装箱

    2021-04-01 09:45:34
    目录 1、基本数据类型 基本数据类型有什么好处 整型的取值范围 超出范围怎么办 2、包装类型 ...7、自动拆装箱与缓存 ...8、自动拆装箱带来的问题 1、基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类

    目录

    1、基本数据类型

    基本数据类型有什么好处

    整型的取值范围

    超出范围怎么办

    2、包装类型

    为什么需要包装类

    3、拆箱与装箱

    4、自动拆箱与自动装箱

    5、自动装箱与自动拆箱的实现原理

    6、哪些地方会自动拆装箱

    场景一、将基本数据类型放入集合类

    场景二、包装类型和基本类型的大小比较

    场景三、包装类型的运算

    场景四、三目运算符的使用

    场景五、函数参数与返回值

    7、自动拆装箱与缓存

    8、自动拆装箱带来的问题


    1、基本数据类型

    基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型。它们是我们编程中使用最频繁的类型。

    Java是一种强类型语言,第一次申明变量必须说明数据类型,第一次变量赋值称为变量的初始化。

    Java基本类型共有八种,基本类型可以分为三类:

    字符类型char

    布尔类型boolean

    整数类型byteshortintlong

    浮点数类型floatdouble

    Java中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。

    基本数据类型有什么好处

    我们都知道在Java语言中,new一个对象是存储在堆里的,我们通过栈中的引用来使用这些对象;所以,对象本身来说是比较消耗资源的。

    对于经常用到的类型,如int等,如果我们每次使用这种变量的时候都需要new一个Java对象的话,就会比较笨重。

    所以,和C++一样,Java提供了基本数据类型,这种数据的变量不需要使用new创建,他们不会在堆上创建,而是直接在栈内存中存储,因此会更加高效。

    整型的取值范围

    Java中的整型主要包含byteshortintlong这四种,表示的数字范围也是从小到大的,之所以表示范围不同主要和他们存储数据时所占的字节数有关。

    先来个简答的科普,1字节=8位(bit)。java中的整型属于有符号数。

    先来看计算中8bit可以表示的数字:

    1. 最小值:10000000 (-128)(-2^7)

    2. 最大值:01111111(127)(2^7-1)

    整型的这几个类型中,

    • byte:byte用1个字节来存储,范围为-128(-2^7)到127(2^7-1),在变量初始化的时候,byte类型的默认值为0。

    • short:short用2个字节存储,范围为-32,768 (-2^15)到32,767 (2^15-1),在变量初始化的时候,short类型的默认值为0,一般情况下,因为Java本身转型的原因,可以直接写为0。

    • int:int用4个字节存储,范围为-2,147,483,648 (-2^31)到2,147,483,647 (2^31-1),在变量初始化的时候,int类型的默认值为0。

    • long:long用8个字节存储,范围为-9,223,372,036,854,775,808 (-2^63)到9,223,372,036, 854,775,807 (2^63-1),在变量初始化的时候,long类型的默认值为0L或0l,也可直接写为0。

    超出范围怎么办

    上面说过了,整型中,每个类型都有一定的表示范围,但是,在程序中有些计算会导致超出表示范围,即溢出。如以下代码:

    int i = Integer.MAX_VALUE;
    int j = Integer.MAX_VALUE;
    int k = i + j;
    System.out.println("i (" + i + ") + j (" + j + ") = k (" + k + ")");

    输出结果:i (2147483647) + j (2147483647) = k (-2)

    这就是发生了溢出,溢出的时候并不会抛异常,也没有任何提示。所以,在程序中,使用同类型的数据进行运算的时候,一定要注意数据溢出的问题。

    2、包装类型

    Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。

    包装类均位于java.lang包,包装类和基本数据类型的对应关系如下表所示

    基本数据类型包装类
    byteByte
    booleanBoolean
    shortShort
    charCharacter
    intInteger
    longLong
    floatFloat
    doubleDouble

    在这八个类名中,除了Integer和Character类以后,其它六个类的类名和基本数据类型一致,只是类名的第一个字母大写即可。

    为什么需要包装类

    很多人会有疑问,既然Java中为了提高效率,提供了八种基本数据类型,为什么还要提供包装类呢?

    这个问题,其实前面已经有了答案,因为Java是一种面向对象语言,很多地方都需要使用对象而不是基本数据类型。比如,在集合类中,我们是无法将int 、double等类型放进去的。因为集合的容器要求元素是Object类型。

    为了让基本类型也具有对象的特征,就出现了包装类型,它相当于将基本类型“包装起来”,使得它具有了对象的性质,并且为其添加了属性和方法,丰富了基本类型的操作。

    3、拆箱与装箱

    那么,有了基本数据类型和包装类,肯定有些时候要在他们之间进行转换。比如把一个基本数据类型的int转换成一个包装类型的Integer对象。

    我们认为包装类是对基本类型的包装,所以,把基本数据类型转换成包装类的过程就是打包装,英文对应于boxing,中文翻译为装箱。

    反之,把包装类转换成基本数据类型的过程就是拆包装,英文对应于unboxing,中文翻译为拆箱。

    在Java SE5之前,要进行装箱,可以通过以下代码:

    Integer i = new Integer(10);
    

    4、自动拆箱与自动装箱

    在Java SE5中,为了减少开发人员的工作,Java提供了自动拆箱与自动装箱功能。

    自动装箱: 就是将基本数据类型自动转换成对应的包装类。

    自动拆箱:就是将包装类自动转换成对应的基本数据类型。

    Integer i =10;  //自动装箱
    int b= i;     //自动拆箱

    Integer i=10 可以替代 Integer i = new Integer(10);,这就是因为Java帮我们提供了自动装箱的功能,不需要开发者手动去new一个Integer对象。

    5、自动装箱与自动拆箱的实现原理

    既然Java提供了自动拆装箱的能力,那么,我们就来看一下,到底是什么原理,Java是如何实现的自动拆装箱功能。

    我们有以下自动拆装箱的代码:

    public static  void main(String[]args){
    
        Integer integer=1; //装箱
    
        int i=integer; //拆箱
    
    }

    对以上代码进行反编译后可以得到以下代码:

    public static  void main(String[]args){
    
        Integer integer=Integer.valueOf(1); 
    
        int i=integer.intValue(); 
    
    }

    从上面反编译后的代码可以看出,int的自动装箱都是通过Integer.valueOf()方法来实现的,Integer的自动拆箱都是通过integer.intValue来实现的。如果读者感兴趣,可以试着将八种类型都反编译一遍 ,你会发现以下规律:

    自动装箱都是通过包装类的valueOf()方法来实现的.自动拆箱都是通过包装类对象的xxxValue()来实现的。

    6、哪些地方会自动拆装箱

    我们了解过原理之后,在来看一下,什么情况下,Java会帮我们进行自动拆装箱。前面提到的变量的初始化和赋值的场景就不介绍了,那是最简单的也最容易理解的。

    我们主要来看一下,那些可能被忽略的场景。

    场景一、将基本数据类型放入集合类

    我们知道,Java中的集合类只能接收对象类型,那么以下代码为什么会不报错呢?

    List<Integer> li = new ArrayList<>();
    
    for (int i = 1; i < 50; i ++){
    
        li.add(i);
    
    }

    将上面代码进行反编译,可以得到以下代码:

    List<Integer> li = new ArrayList<>();
    
    for (int i = 1; i < 50; i += 2){
    
        li.add(Integer.valueOf(i));
    
    }

    以上,我们可以得出结论,当我们把基本数据类型放入集合类中的时候,会进行自动装箱。

    场景二、包装类型和基本类型的大小比较

    有没有人想过,当我们对Integer对象与基本类型进行大小比较的时候,实际上比较的是什么内容呢?看以下代码:

    Integer a=1;
    
    System.out.println(a==1?"等于":"不等于");
    
    Boolean bool=false;
    
    System.out.println(bool?"真":"假");

    对以上代码进行反编译,得到以下代码:

    Integer a=1;
    
    System.out.println(a.intValue()==1?"等于":"不等于");
    
    Boolean bool=false;
    
    System.out.println(bool.booleanValue?"真":"假");

    可以看到,包装类与基本数据类型进行比较运算,是先将包装类进行拆箱成基本数据类型,然后进行比较的。

    场景三、包装类型的运算

    有没有人想过,当我们对Integer对象进行四则运算的时候,是如何进行的呢?看以下代码:

    Integer i = 10;
    
    Integer j = 20;
    
    
    System.out.println(i+j);

    反编译后代码如下:

    Integer i = Integer.valueOf(10);
    
    Integer j = Integer.valueOf(20);
    
    System.out.println(i.intValue() + j.intValue());

    我们发现,两个包装类型之间的运算,会被自动拆箱成基本类型进行。

    场景四、三目运算符的使用

    这是很多人不知道的一个场景。看一个简单的三目运算符的代码:

    boolean flag = true;
    
    Integer i = 0;
    
    int j = 1;
    
    int k = flag ? i : j;

    很多人不知道,其实在int k = flag ? i : j;这一行,会发生自动拆箱。反编译后代码如下:

    boolean flag = true;
    
    Integer i = Integer.valueOf(0);
    
    int j = 1;
    
    int k = flag ? i.intValue() : j;

    这其实是三目运算符的语法规范:当第二,第三位操作数分别为基本类型和对象时,其中的对象就会拆箱为基本类型进行操作。

    因为例子中,flag ? i : j;片段中,第二段的i是一个包装类型的对象,而第三段的j是一个基本类型,所以会对包装类进行自动拆箱。如果这个时候i的值为null,那么久会发生NPE。(自动拆箱导致空指针异常

    场景五、函数参数与返回值

    这个比较容易理解,直接上代码了:

    //自动拆箱
    
    public int getNum1(Integer num) {
    
     return num;
    
    }
    
    //自动装箱
    
    public Integer getNum2(int num) {
    
     return num;
    
    }
    
    

    7、自动拆装箱与缓存

    Java SE的自动拆装箱还提供了一个和缓存有关的功能,我们先来看以下代码,猜测一下输出结果:

    public static void main(String... strings) {
    
        Integer integer1 = 3;
        Integer integer2 = 3;
    
        if (integer1 == integer2)
            System.out.println("integer1 == integer2");
    
        else
            System.out.println("integer1 != integer2");
    
        Integer integer3 = 300;
        Integer integer4 = 300;
    
        if (integer3 == integer4)
            System.out.println("integer3 == integer4");
    
        else
            System.out.println("integer3 != integer4");
    }

    我们普遍认为上面的两个判断的结果都是false。虽然比较的值是相等的,但是由于比较的是对象,而对象的引用不一样,所以会认为两个if判断都是false的。

    在Java中,==比较的是对象应用,而equals比较的是值。

    所以,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都将返回false。奇怪的是,这里两个类似的if条件判断返回不同的布尔值。

    上面这段代码真正的输出结果:

    integer1 == integer2
    
    integer3 != integer4

    原因就和Integer中的缓存机制有关。在Java 5中,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。

    适用于整数值区间-128 至 +127。

    只适用于自动装箱。使用构造函数创建对象不适用。

    具体的代码实现可以阅读自动装箱与缓存一文,这里不再阐述。

    我们只需要知道,当需要进行自动装箱时,如果数字在-128至127之间时,会直接使用缓存中的对象,而不是重新创建一个对象。

    其中的javadoc详细的说明了缓存支持-128到127之间的自动装箱过程。最大值127可以通过-XX:AutoBoxCacheMax=size修改。

    实际上这个功能在Java 5中引入的时候,范围是固定的-128 至 +127。后来在Java 6中,可以通过java.lang.Integer.IntegerCache.high设置最大值。

    这使我们可以根据应用程序的实际情况灵活地调整来提高性能。到底是什么原因选择这个-128到127范围呢?因为这个范围的数字是最被广泛使用的。 在程序中,第一次使用Integer的时候也需要一定的额外时间来初始化这个缓存。

    8、自动拆装箱带来的问题

    当然,自动拆装箱是一个很好的功能,大大节省了开发人员的精力,不再需要关心到底什么时候需要拆装箱。但是,他也会引入一些问题。

    包装对象的数值比较,不能简单的使用==,虽然-128到127之间的数字可以,但是这个范围之外还是需要使用equals比较。

    前面提到,有些场景会进行自动拆装箱,同时也说过,由于自动拆箱,如果包装类对象为null,那么自动拆箱时就有可能抛出NPE。

    如果一个for循环中有大量拆装箱操作,会浪费很多资源。

    展开全文
  • 目录 基本数据类型 八大数据类型 Java类型分类 基本类型: 引用类型: void类型 使用基本数据类型的好处 包装类型 创建对象方法 Byte Boolean Short Character ...自动拆装箱的实现原...

    目录

    基本数据类型

    八大数据类型

    Java类型分类

            基本类型:

            引用类型:

    void类型

    使用基本数据类型的好处

    包装类型

    创建对象方法

    Byte

    Boolean

    Short

    Character

    Integer

    Long

    Float

    Double

    为什么需要包装类

    装箱与拆箱

    装箱与拆箱

            装箱:

            拆箱:

    自动拆装箱

            自动装箱:

            自动拆箱:

    自动拆装箱的实现原理

    自动拆装箱使用场景

            1.将基本类型放入集合类

            2.包装类型和基本类型比较大小

            3.包装类型的运算

            4.三目运算符的使用

            5.函数参数与返回值

    自动拆装箱与缓存

     自动拆装箱带来的问题


    基本数据类型

    八大数据类型

    字符型                                                        char

    布尔类型                                                     boolean

    整数类型                                                     byte、short、int、long

    浮点数类型                                                  float、double

    Java类型分类

            基本类型:

                    在JVM栈中分配空间存值

            引用类型:

                    在堆中分配空间存值

    void类型

    Java还存在一种基本类型void,对应的包装类为java.lang.Void,Void是不能被new出来的

    因此不能在堆中分配存储空间存储对应的值

    使用基本数据类型的好处

    在Jva语言中,new一个对象是存储在堆中的,我们通过栈中的引用来使用这些对象,是比较费资源的

    而常用的基本数据类型,不需要用new创建,数据直接存放在栈中,所以会更加高效

     我们可以知道,在栈中每一个栈帧,都包含了局部变量表,这里局部变量中的数据,就是存储在局部变量表中的

    包装类型

    基本数据类型包装类
    byteByte
    booleanBoolean
    shortShort
    charCharacter
    intInteger
    longLong
    floatFloat
    doubleDouble

    创建对象方法

    Byte

    public class Test04 {
        public static void main(String[] args) {
            Byte a = 2;                                    //通过自动装箱赋值
            Byte b = new Byte(String.valueOf(1));         //通过String创建对象
        }
    }

    Boolean

    public class Test04 {
        public static void main(String[] args) {
            Boolean a = true;          //通过valueOf赋值
            Boolean c = new Boolean(String.valueOf(true));          //通过String
            Boolean b = new Boolean(true);                 //通过常数
        }
    }

    Short

    public class Test04 {
        public static void main(String[] args) {
            Short a = 1;                                    //通过自动装箱赋值
            Short b = new Short(String.valueOf(1));         //通过String创建对象
        }
    }

    Character

    public class Test04 {
        public static void main(String[] args) {
            Character a = '1';          //通过valueOf赋值
            Character b = new Character('1');                 //通过常数
        }
    }
    

    Integer

    public class Test04 {
        public static void main(String[] args) {
            Integer a = 2;                                    //通过自动装箱赋值
            Integer b = new Integer(1);                 //通过常数
            Integer c = new Integer(String.valueOf(1));       //通过String创建对象
        }
    }
    

    Long

    public class Test04 {
        public static void main(String[] args) {
            Long a = Long.valueOf(2);                   //通过valueOf赋值
            Long b = new Long(1);                 //通过常数
            Long c = new Long(String.valueOf(1));       //通过String创建对象
        }
    }
    

    Float

    public class Test04 {
        public static void main(String[] args) {
            Float a = Float.valueOf((float) 2.1);          //通过valueOf赋值
            Float b = new Float(1.5);                 //通过常数
            Float c = new Float(String.valueOf(1));       //通过String创建对象
        }
    }

    Double

    public class Test04 {
        public static void main(String[] args) {
            Double a = Double.valueOf((Double) 2.1);          //通过valueOf赋值
            Double b = new Double(1.5);                 //通过常数
            Double c = new Double(String.valueOf(1));       //通过String创建对象
        }
    }
    

    为什么需要包装类

    Java是面向对象的语言,很多地方都是需要使用对象而不是剧本数据类型的

            比如在集合类中,我们无法将int等数据类型放进去,因为集合的容器要求元素是Object类型

    为了让基本类型也具有对象特性,就出现了包装类型,丰富了基本类型的操作

    装箱与拆箱

    装箱与拆箱

            装箱:

                    把基本类型转换为包装类的过程就是装箱

            拆箱:

                    把包装类转换为基本数据类型就是拆箱

    自动拆装箱

    在JavaSE5中,为了减少开发人员的工作,Java提供了自动拆装箱功能

            自动装箱:

                    将基本数据类型自动转化为对应的包装类

            自动拆箱:

                    将包装类自动转化成对应的基本数据类型

    自动拆装箱的实现原理

            自动装箱都是通过包装类的valueOf方法实现的

            自动装箱都是通过包装类对象xxxValue方法实现的(如intValue)

    自动拆装箱使用场景

            1.将基本类型放入集合类

                    集合类中都是对象类型,但是我们add(基本数据类型)也不会报错,是因为Java给我们做了自动装箱

            2.包装类型和基本类型比较大小

                    包装类与基本数据类型进行比较运算,先将包装类进行拆箱成基本数据类型,然后比较

            3.包装类型的运算

                    对两个包装类型进行运算,会将包装类型自动拆箱为基本类型进行

            4.三目运算符的使用

                    如

    falg?i:j

            5.函数参数与返回值

    //自动拆箱
    public int getNum1(Integer num) {
     return num;
    }
    //自动装箱
    public Integer getNum2(int num) {
     return num;
    }

    自动拆装箱与缓存

    在Java SE5中,Integer操作引入了新功能来节省内存和提高性能

            1.适用于整数区间-128~+127

            2.只适用于自动装箱,使用构造函数创建对象不适用

            3.只适用于整形,浮点型不行

    public class Test04 {
        public static void main(String[] args) {
            //不创建对象且在-128~127中
            Integer a = 1;
            Integer b = 1;
            System.out.println(a == b);        //true
            //创建对象且在-128~127中
            Integer c = new Integer(1);
            Integer d = new Integer(1);
            System.out.println(c == d);        //fasle
            //不创建对象且不在-128~127中
            Integer e = 200;
            Integer f = 200;
            System.out.println(e == f);        //false
        }
    }
    

     自动拆装箱带来的问题

            1.包装对象之间的数值比较不能简单的使用==,除了特殊情况(如Integer的-128~127),其他比较都需要使用equals比较

            2.如果包装类对象为NULL,那么自动拆箱就可能会抛出NPE

            3.如果一个for循环中有大量拆装箱操作,会浪费很多资源

    参考文章

    什么是Java中的自动拆装箱_HelloWorld搬运工-CSDN博客_java自动拆装箱

    Java 中基本数据类型是 8 种还是 9 种? Void 的解释._话流年的博客-CSDN博客_void是不是基本数据类型

    展开全文
  • java自动拆装箱 | Path

    2021-03-14 21:24:12
    ++自动拆装箱的问题引入由于在一开始学习java的时候,”万物皆对象“这种面向对象的看问题方式,时刻围绕在脑海中。因为静态的变量和基本数据类型不属于对象,但是由8种基本数据类型的自动装拆箱解决了基本数据类型...

    +

    +

    +

    +

    +

    +

    所有文章出现的代码,将会出现在我的github中,名字可以根据类全名来找,我在github中的文件夹也会加目录备注。

    +

    +

    自动拆装箱的问题引入

    由于在一开始学习java的时候,”万物皆对象“这种面向对象的看问题方式,时刻围绕在脑海中。因为静态的变量和基本数据类型不属于对象,但是由8种基本数据类型的自动装拆箱解决了基本数据类型不是对象。

    +

    在jdk1.5中引入了自动拆装箱的新特性,在jdk1.5之前,我们想要使用integer类中的方法,我们先要把int变量变成integer类型,可以通过new Integer(intNumber) 或者调用Integer.valueOf(intNumber)方法

    +

    自动装拆箱何时发生?

    在调用方法时把基本数据类型作为参数,但是参数的类型是基本数据类型的包装类时。

    在学习过javaSe基础之后,我们知道通过使用集合框架ArrayList或者Map来添加元素的时候,添加的是Object对象,在这里引入ArrayList.add()的源码:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11/**

    * Appends the specified element to the end of this list.

    *

    * @param e element to be appended to this list

    * @return true (as specified by {@link Collection#add})

    */

    public boolean add(E e){

    ensureCapacity(size + 1); // Increments modCount!!

    elementData[size++] = e;

    return true;

    }

    +

    对于源码的解读:首先我们来看看参数中的(E e),为什么是E?而不是Object?因为E代表的是元素(集合中存储的是元素),我们平时在泛型中可以看到 >,T 代表的是Type 类,再比如键值对中的Map,K 表示的是Key,V 表示的是Value。E K V 等泛型在使用该参数之前就已经限定好了类型,如果赋值给Object的话,就不用再进行强制类型转换了。

    +

    首先把数组的长度+1,这个操作会导致modCount加一,这个变量的作用就是记录当前数组被操作的次数,然后直接把参数传进来的对象赋值给上一次长度位置的元素。返回true表示添加成功

    +

    当我们调用ArrayList.add()方法的时候,可以直接调用

    +1

    2ArrayList arrayList = new ArrayList();

    arrayList.add(10);

    +

    反编译这段代码:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13public class AutoboxingTest

    {

    public AutoboxingTest()

    {

    }

    public static void main(String args[])

    {

    ArrayList arrayList = new ArrayList();

    arrayList.add(Integer.valueOf(100));

    }

    }

    +

    可以看到,编译器在编译的时候,检测到arrayList.add()需要的是Integer对象,所以把int类型自动装箱成Integer类型。

    +

    给基本数据类型的包装类赋值为基本数据类型的时候。

    以Integer和int类型的变量作为例子:

    +1

    2

    3

    4

    5

    6public class AutoboxingTest2{

    public static void main(String[] args){

    Integer integer = 10;

    }

    }

    +

    反编译例子:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12public class AutoboxingTest2

    {

    public AutoboxingTest2()

    {

    }

    public static void main(String args[])

    {

    Integer integer = Integer.valueOf(10);

    }

    }

    +

    什么时候自动装箱不起作用

    例子1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18public class InvalidateAutoboxing{

    public void print(int num){

    System.out.println("i am int !");

    }

    public void print(Integer num){

    System.out.println("i am integer!");

    }

    }

    public class InvalidateAutoboxingTest{

    public static void main(String[] args){

    InvalidateAutoboxing invalidateAutoboxing = new InvalidateAutoboxing();

    invalidateAutoboxing.print(5);

    }

    }

    +

    运行结果:

    +

    20160302225248708.png

    +

    使用自动装箱拆箱需要注意的地方

    循环与自动装箱拆箱1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12public class CirculateAndAutoboxingAndAutounboxing{

    public static void main(String[] args){

    Integer sum = 0;

    for (int i = 0; i < 200; i++) {

    sum += i;

    }

    }

    }

    +

    反编译:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15public class CirculateAndAutoboxingAndAutounboxing

    {

    public CirculateAndAutoboxingAndAutounboxing()

    {

    }

    public static void main(String args[])

    {

    Integer sum = Integer.valueOf(0);

    for(int i = 0; i < 200; i++)

    sum = Integer.valueOf(sum.intValue() + i);

    }

    }

    +

    反编译代码解读:由于sum是Integer类型,但是sum+=i 需要sum先自动拆箱成int类型(调用intValue()方法),进行相加之后,再自动装箱成Integer类型把结果赋给sum。

    +

    Integer.valueOf源码解析:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20/**

    * Returns a Integer instance representing the specified

    * int value.

    * If a new Integer instance is not required, this method

    * should generally be used in preference to the constructor

    * Integer(int), as this method is likely to yield

    * significantly better space and time performance by caching

    * frequently requested values.

    *

    * @param i an int value.

    * @return a Integer instance representing i.

    * @since 1.5

    */

    public static Integer valueOf(int i){

    final int offset = 128;

    if (i >= -128 && i <= 127) { // must cache

    return IntegerCache.cache[i + offset];

    }

    return new Integer(i);

    }

    +

    首先我们在源码说明中看到了该构造器缓存经常使用的数据以减少内存的使用和提高效率,Integer把缓冲区的上限脚标设置成128,如果传进来的数据i在-128~127之中,直接返回缓冲区中的IntegerCache.cache[i + 128] 位中的元素

    +

    IntegerCache的源码解读:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10private static class IntegerCache{

    private IntegerCache(){}

    static final Integer cache[] = new Integer[-(-128) + 127 + 1];

    static {

    for(int i = 0; i < cache.length; i++)

    cache[i] = new Integer(i - 128);

    }

    }

    +

    IntegerCache是Integer的内部类,并且内部数组的上限为256元素,在这个内部类中使用了静态代码块(在类加载的时只执行一次),把-128~127都缓存在数组中。所以以后调用的时候就可以直接返回Integer对象,而不用return new Integer(i); Integer Short Long的缓冲数组是一样的,但是Character的范围为0~127,Double和Float没有缓冲数组

    +

    话又说回来,刚刚我们在分析循环与自动装拆箱的使用需要注意:当参与的数值不在缓存的范围内,会产生大量的对象,这样会产生很多垃圾对象,增加GC的工作压力。

    +

    自动装拆箱与三元运算符造成的空指针异常(NPE)1

    2

    3

    4

    5

    6

    7

    8

    9public class AutounboxingWithConditionalOperator{

    public static void main(String[] args){

    HashMap hashMap = new HashMap();

    Boolean b = (hashMap != null ? hashMap.get("test") : false);

    }

    }

    +

    运行:

    +

    20160302233303149.png

    +

    如果在Map中添加了test这条数据:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10public class AutounboxingWithConditionalOperator{

    public static void main(String[] args){

    HashMap hashMap = new HashMap();

    hashMap.put("test", true);

    Boolean b = (hashMap != null ? hashMap.get("test") : false);

    System.out.println(b);

    }

    }

    +

    运行:

    +

    20160302233610988.png

    +

    再反编译刚刚NPE异常的代码:

    +1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13public class AutounboxingWithConditionalOperator

    {

    public AutounboxingWithConditionalOperator()

    {

    }

    public static void main(String args[])

    {

    HashMap hashMap = new HashMap();

    Boolean b = Boolean.valueOf(hashMap == null ? false : ((Boolean)hashMap.get("test")).booleanValue());

    }

    }

    +

    下面是hashMap.get(key)方法的说明:

    ++

    Returns the value to which the specified key is mapped,

    +

    or null if this map contains no mapping for the key.

    +

    +

    由上面可以看出,由于Map.get(key)方法,如果没有指定的数据,返回的是null。

    +

    再由于三元运算符有如下定义:

    ++

    The type of a conditional expression is determined as follows:

    +

    1、If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression.

    +

    2、If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.

    +

    3、If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.

    +

    +

    译文:

    +

    三元运算符的类型由以下情况决定:

    +

    1、如果第二和第三个操作结果拥有同样类型(这个类型可能为null),那么这个类型就是该三元运算符的结果类型

    +

    2、如果第二个操作和第三个操作结果其中一个的结果类型为基本数据类型,另外一个操作结果为可以装箱转换成与前面一种类型一致的包装类,那么这个三元运算符的运算结果类型为基本数据类型,即把包装类拆装。

    +

    3、如果在第二、三个操作结果中,有一个为null类型,另外一个为引用类型,那么这个三元运算符的表达式为引用类型。

    +

    综上所述,对于上面出现的情况,对于一个操作结果为基本类型,另外一个为包装类型的三元运算符表达式来说,为了避免NEP的产生,可以通过把它们变成同样类型(参考三元运算符定义的第一条)。

    +

    一点小思考

    从上面的例子中我们可以看见,java中的基本数据类型是不属于对象的,虽然它们有对应的包装类,可是从上面我们反编译或者从其对应的包装类中对应的源码我们可以看见,它们依然坚持不把基本数据类型当作对象来看待,而不像C#那么“纯”,我想可能是开发者考虑到变量在栈中存储,但是对象在堆中存储,涉及到对象就要涉及到垃圾回收,但是在栈中只要函数弹栈,就释放了空间了,可能也怕加重垃圾回收器的压力。毕竟垃圾回收不是程序员能控制的,我们的开始只是通过更了解JVM来更好的分配空间,为了更好的符合垃圾回收的规律,来让垃圾回收更高效。

    +

    参考资料:

    +

    +

    +

    +

    展开全文
  • 详解Java自动拆装箱

    2022-03-18 16:56:05
    详解Java自动拆装箱
  • 在学习并发的过程中,用“Boolean bool = true”的自动装箱方式初始化了两个对象锁去锁两块代码,结果运行的时候出现了竞争等待,调试了一下发现两个锁变量指向的是同一个对象,由此可见我对自动拆装箱的机制想的太...
  • java中的自动拆装箱

    2021-02-28 12:11:06
    一:是什么java的自动拆装箱,是从jdk1.5之后被引入的,java中的类型分为基本类型和引用类型,而自动拆装箱,可以让基本类型和对应的包装类,无缝转换。先拿最基本的来看。public class UntoBoxing {public static ...
  • C#拆装箱简记

    2022-01-17 14:50:44
    C#装箱和拆箱 装箱(box) 值类型隐式转换为object类型或由此类型实现的任何接口类型的过程。 内部机制: 1.在堆中开辟内存空间。 2.将值类型的数据复制到堆中。 3.返回堆中新分配对象的地址。 例: int a = 10; ...
  • 拆装箱

    2020-07-22 15:10:08
    链接: 什么是Java中的自动拆装箱 为了让“基本数据类型”也具有对象的特征,就出现了“包装类型”,它相当于将基本类型“包装起来”。 装箱:int->Integer,调用Integer类的valueOf(int)方法 拆箱:Integer->int,...
  • 什么是自动拆装箱

    2020-05-26 17:44:31
    } 自动拆装箱带来的问题 当然,自动拆装箱是一个很好的功能,大大节省了开发人员的精力,不再需要关心到底什么时候需要拆装箱。但是,他也会引入一些问题。 包装对象的数值比较,不能简单的使用==,虽然-128到127...
  • 自动拆装箱

    2021-05-21 02:31:47
    自动装箱与自动拆箱的实现原理 自动拆装箱的代码: public void testBoxing() { Character charObj = 'a'; char charVal = charObj; Boolean booleanObj = true; boolean booleanVal = booleanObj; Byte byteObj = ...
  • 本文主要介绍Java中的自动拆箱与自动装箱的有关知识。基本数据类型基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型。它们是我们编程中使用最频繁的类型。Java是一种强类型语言,第一次申明变量必须...
  • 本文首先介绍java中的基本数据类型,后面详细介绍了自动拆装箱原理,如有问题,欢迎探讨交流。数据类型分类基本数据类型分为三类:数值型:数值型又分为整数型和浮点型;字符型(char)布尔型(boolean)为什么会有基本...
  • 8、自动拆装箱带来的问题 当然,自动拆装箱是一个很好的功能,大大节省了开发人员的精力,不再需要关心到底什么时候需要拆装箱。但是,他也会引入一些问题。 包装对象的数值比较,不能简单的使用==,虽然-128到127...
  • Java 拆装箱与包装类

    2020-10-10 07:05:23
    什么叫拆装箱(Boxing,Unboxing)? 拆装箱就像你包装快递,拆快递一样。 拆装箱的行为作用在包装类上。 装箱就是把基本数据类型转换为包装类。拆箱则是把包装类转换为基础数据类型。 拆装箱给我们提供一种机制,...
  • java自动自动拆装箱

    2021-03-13 01:00:30
    java自动自动拆装箱最近在看Effective-Java-3rd发现其中介绍一个自动拆装箱影响程序的性能问题。自动拆装箱是java 1.5开始新增的功能,它允许程序员混合基本类型和包装类型,根据需要自动装箱和拆箱。但是在性能上面...
  • java中 拆装箱

    2022-03-09 09:18:40
    把包装类转换成基本数据类型的过程就是包装,为拆箱。 Integer a= new Integer(20); int b = a.intValue()等价于 int b = a;相当于把a出来 装箱 我们认为包装类是对基本类型的包装,所以...
  • Java拆装箱深度剖析

    2020-08-31 19:40:13
    主要为大家深度剖析了Java拆箱装箱的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 什么是Java中的自动拆装箱

    万次阅读 多人点赞 2018-09-03 12:47:37
    本文主要介绍Java中的自动拆箱与自动装箱的有关知识。 1、基本数据类型 基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型。它们是我们编程中使用最频繁的类型。 Java是一种强类型语言,第一次...
  • 自动拆装箱带来的问题 当然,自动拆装箱是一个很好的功能,大大节省了开发人员的精力,不再需要关心到底什么时候需要拆装箱。但是,他也会引入一些问题。 包装对象的数值比较,不能简单的使用==,虽然-128到127之间...
  • 拆装箱 Java基础 基本数据类型 包装类型 常见面试题
  • 一文读懂自动拆装箱

    2019-07-29 13:36:00
    本文主要介绍Java中的自动拆箱与自动装箱的有关知识。基本数据类型基本类型,或者叫做内置类型,是Java中不同于类(Class)的特殊类型。它们是我们编程中使用最频繁的类...
  • String常用方法一、包装类1.1 包装类概述1.2 自动拆装箱1.3 手动拆装箱1.4 字符串和基本类型相互转换1.5 关于自动拆装箱的面试题二、字符串常用API2.1 concat2.2 contains2.3 startsWith & endsWith2.4 indexOf ...
  • 自动拆装箱在Java5(就是Java1.5,后边改了命名)时被引入,自动装箱就是Java自动将基础类型值转换成对应的包装类对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个...
  • 背景有Java基础的同学都知道Java中有Primitive Type(原始类型),比如int、short。...为了方便大家写代码,JDK 5以后引入了自动拆装箱的机制. 比如对于函数:add(Integer a)我们在调用的时候,传一个Intege...
  • 拆箱其实直接将对象的值赋值, 比如Integer zz = new Integer(i); int i = i; 自动装箱,就是实现了一个valueof()方法,返回new Integer();

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 16,125
精华内容 6,450
关键字:

拆装箱