深入理解Java之装箱与拆箱

开发 后端
在说装箱与拆箱之前,先说一下Java的基本数据类型,Java从数据类型上可以划分为值类型与引用类型。

一、Java数据类型

1、在说装箱与拆箱之前,先说一下Java的基本数据类型,Java从数据类型上可以划分为值类型与引用类型,值类型是四类八种,分别是:

  •  整数型:byte̵,short̵,int̵,long
  •  浮点型:float,double
  •  字符型:char
  •  布尔型:boolean
数据类型 内存 默认值 包装类
byte 8位 0 Byte
short 16位 0 short
int 32位 0 Integer
long 64位 0L或0l Long
float 32位 0.0F或0.0f Float
double 64位 0.0D或0.0d Double
char 16位 \u0000 Character
boolean 8位 flase Boolean

2、引用类型:

  •  数组
  •  类(class)
  •  接口(Interface)
  •  枚举(enum)

3、值类型与引用类型的区别

   1.  从概念方面上来说:

  •  值类型:变量名指向具体的值
  •  引用类型:变量名指向数据对象的内存地址

   2.  从内存构建方面上来说:

  •  值类型:变量在声明之后,Java就会立刻分配给它内存空间
  •  引用类型:它以特殊的方式(类似C指针)指向对象实体,这类变量声明时不会分配内存,只是存储

   3.  从使用方面上来说:

  •  值类型:使用时需要赋具体值,判断时用 ” == “号
  •  引用类型:使用时可以赋null,判断时使用 equals 方法

二、Java数据类型转换

1、自动转换

  •     定义:程序在执行过程中“悄然”进行的转换,不需要用户提前声明,一般是从位数低的类型向位数高的类型转换
  •     优先关系:按从低到高的顺序转换。不同类型数据间的优先   关系如下:
    •  低--------------------------------------------->高
    •  byte,short,char-> int -> long -> float -> double
  •  转换规则:

    运算中,不同类型的数据先转化为同一类型,然后进行运算   

操作数1类型 操作数2类型 转换后的类型
byte、short、char int int
byte、short、char、int long long
byte、short、char、int、long float float
byte、short、char、int、long、float double double

2、强制转换

  •  定义:强制类型转换则必须在代码中声明,转换顺序不受限制
  •  格式:在需要转型的数据前加上“( )”,然后在括号内加入需要转化的数据类型
  •  结果:精度可能会丢失,也可能更加精确 
  1. int x;  
  2.  double y;  
  3.  x = (int)3.14 + (int)5.20  //精度丢失  
  4.  y = (double)x + (double)8  //精度提升  
  5.  输出:x = 8;y = 16.0 

三、Java之装箱与拆箱

1、包装类

  •  Java是面向对象语言,号称万事万物皆对象,因此,8种基本数据类型有了对应的类,这就是包装类

2、什么是装箱与拆箱

  •  装箱:将值类型装换成引用类型的过程
  •  拆箱:将引用类型转换成值类型的过程
  •  自动装箱:   
  1. int x = 3 
  2.    Integer y = x;  //int --> Integer,Integer y = x <==> Integer y = Integer.valueOf(x) 
  •  自动拆箱:   
  1. Integer x = new Integer(5);  
  2.    int y = x;  //Integer --> int,int y = x <==> int y = x.intValue() 

3、装箱和拆箱是如何实现的

  •  装箱过程是通过调用包装器的valueOf方法实现的
  •  拆箱过程是通过调用包装器的 xxxValue方法实现的。(xxx代表对应的基本数据类型)

4、注意点:

  1.  大量使用自动拆装箱会使性能降低,还会造成大量的内存消耗
  2.  在重载方法中,可能出现问题 
  1. List<Integer> list = new ArrayList<>();  
  2.   Integer x,y,z;  
  3.   x = 1;y = 2;z = 4 
  4.   list.add(x);list.add(y);list.add(z);  
  5.   list.remove(2); 

在上面这段代码中ArrayList.remove方法有两个重载方法,那么list.remove(2)是调用了哪个方法,remove掉的是值为2的对象,还是remove了index为2,值为4的那个对象呢?

在这种情况下,编译器不会进行自动拆装箱,所以调用的是remove(int index),index为2值为4的这个Integer对象会被remove.

如果要调用 remove(Object o)的方法,应该这么写 list.remove(y)

    3.  缓存值问题

  •  案例解析:   
  1. Integer i1 = 100 
  2.    Integer i2 = 100 
  3.    Integer i3 = 200 
  4.    Integer i4 = 200 
  5.    System.out.println(i1==i2);  
  6.    System.out.println(i3==i4);  
  7.    Output: true false 
  •  观察源码:

    Intteger.valueOf方法   

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

IntegerCache类   

  1. private static class IntegerCache { 
  2.        static final int low = -128;  
  3.        static final int high;  
  4.        static final Integer cache[];  
  5.        static {  
  6.            // high value may be configured by property  
  7.            int h = 127 
  8.            String integerCacheHighPropValue =  
  9.                sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");  
  10.            if (integerCacheHighPropValue != null) {  
  11.                try {  
  12.                    int i = parseInt(integerCacheHighPropValue);  
  13.                    i = Math.max(i, 127);  
  14.                    // Maximum array size is Integer.MAX_VALUE  
  15.                    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);  
  16.                } catch( NumberFormatException nfe) {  
  17.                    // If the property cannot be parsed into an int, ignore it.  
  18.                }  
  19.            }  
  20.            hhigh = h;  
  21.            cache = new Integer[(high - low) + 1];  
  22.            int j = low 
  23.            for(int k = 0; k < cache.length; k++)  
  24.                cache[k] = new Integer(j++);  
  25.            // range [-128, 127] must be interned (JLS7 5.1.7)  
  26.            assert IntegerCache.high >= 127;  
  27.        }  
  28.        private IntegerCache() {}  
  29.    } 

从源码可以看出,在通过valueOf方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象

  •  Byte、Short、Integer、Long四种包装类默认创建了数值为[-128,127]的相应类型的缓存数据,但是超出此范围仍会创建新的对象。
  •  Character默认会创建[0,127]的响应类型的缓存数据
  •  两种浮点型没有实现常量池技术,在某个范围内的整型数值的个数是有限的,而浮点数却不是   
包装类 常量池 常量池范围
Byte 存在 [-128,127]
Short 存在 [-128,127]
Integer 存在 [-128,127]
Long 存在 [-128,127]
Character 存在 [0,127]
Float 不存在
Double 不存在
  •  注意点:
    •   当 "=="运算符的两个操作数都是 包装器类型的引用,则是比较指向的是否是同一个对象,而如果其中有一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)
    •  对于包装器类型,equals方法并不会进行类型转换
    •  算术运算会触发装箱与拆箱过程 

 

责任编辑:庞桂玉 来源: Linux公社
相关推荐

2015-09-02 10:12:54

Java自动装箱拆箱

2021-09-06 14:30:34

C#装箱拆箱

2009-08-26 03:39:00

C#装箱和拆箱

2012-03-26 11:32:45

Java

2021-02-17 11:25:33

前端JavaScriptthis

2009-08-28 11:22:11

C#装箱和拆箱

2009-08-06 15:40:11

C#装箱和拆箱

2010-03-12 08:55:06

Java内省反射

2022-09-05 22:22:00

Stream操作对象

2017-11-14 14:41:11

Java泛型IO

2009-09-01 17:51:47

C#拆箱C#装箱

2019-03-18 09:50:44

Nginx架构服务器

2018-12-27 12:34:42

HadoopHDFS分布式系统

2014-12-04 14:01:54

openstacknetworkneutron

2024-06-28 10:25:18

2024-03-15 15:03:23

2021-09-24 08:10:40

Java 语言 Java 基础

2016-12-08 15:36:59

HashMap数据结构hash函数

2020-07-21 08:26:08

SpringSecurity过滤器

2010-06-01 15:25:27

JavaCLASSPATH
点赞
收藏

51CTO技术栈公众号