Java中的拆箱和装箱

首先说一下Java中的包装类,Java语言是一个面向对象的语言,但是Java中的基本数据类型却不是面向对象的,这在实际使用时存在很多的不便(比如,我们不能直接想集合Collections中放入原始类型值,因为集合只接收对象)。为了解决这个不足,在设计类的是为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。


基本数据类型


包装类


byte


Byte


boolean


Boolean


short


Short


char


Character


int


Integer


long


Long


float


Float


double


Double

自动装箱就是Java自动将原始类型转化为对应的对象,比如将int的变量转化为Integer对象,这个过程叫做装箱,反之将Integer对象转化为int对象,这个过程叫做拆箱。又因为这个过程是自动发生的,所以又叫自动装箱,自动拆箱。

ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(1);  //自动装箱 int --> Integer

int number = arrayList.get(0);     //自动拆箱   Integer  -->  int

简单点说,装箱就是自动将基本类型转化为包装类型,拆箱就是自动将包装类型转化为基本类型。

在自动装箱的过程中,系统为我们执行了

Integer total = Integer.valueOf(1);

自动拆箱的过程中,系统为我们执行了

int number = total.intValue();

弊端:

  有些情况中,自动装箱如果不注意的话会创建多余的对象,影响程序的性能。

Integer sum = 0;
 for(int i=1000; i<5000; i++){
   sum+=i;
}

  上述代码中 sum+=i 可以看成 sum = sum +i,但是这个 + 操作符不适用与Integer对象,首先sum进行自动拆箱操作,进行数值的相加操作,最后发生自动装箱操作转化为Integer对象。

其内部的变化如下:

sum = sum.intValue() + i;
Integer sum = new Integer(result);

由于我们声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的对象,在这样庞大的循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我们编程时,需要注意到这一点,正确的声明变量类型,避免因为自动装箱引起的性能问题。

在Integer类内部包含了一些和int操作有关的方法,下面介绍一些比较常用的方法:

a、parseInt方法

public static int parseInt(String s)

该方法的作用是将数字字符串转换为int数值。在以后的界面编程中,将字符串转换为对应的int数字是一种比较常见的操作。使用示例如下:

String s = “123”;

int n = Integer.parseInt(s);

则int变量n的值是123,该方法实际上实现了字符串和int之间的转换,如果字符串都包含的不是都是数字字符,则程序执行将出现异常。

另外一个parseInt方法:

public static int parseInt(String s, int radix)

则实现将字符串按照参数radix指定的进制转换为int,使用示例如下:

//将字符串”120”按照十进制转换为int,则结果为120

int n = Integer.parseInt(“120”,10);

//将字符串”12”按照十六进制转换为int,则结果为18

int n = Integer.parseInt(“12”,16);

//将字符串”ff”按照十六进制转换为int,则结果为255

int n = Integer.parseInt(“ff”,16);

这样可以实现更灵活的转换。

b、toString方法

public static String toString(int i)

该方法的作用是将int类型转换为对应的String类型。

使用示例代码如下:

int m = 1000;

String s = Integer.toString(m);

则字符串s的值是”1000”。

另外一个toString方法则实现将int值转换为特定进制的字符串:

public static int parseInt(String s, int radix)

使用示例代码如下:

int m = 20;

String s = Integer.toString(m);

则字符串s的值是”14”。

另外说一个前两天遇到的问题

  int i = Integer.valueOf("222");
        System.out.println(i);

在用findbugs查到了这个问题,进行了多余的拆箱和装箱操作,原因是 Interger.valuesOf("")返回的是 Integer对象,然后再拆箱到 int类型。

看几个例子

        int i = 128;
        Integer i2 = 128;
        Integer i3 = new Integer(128);
        //Integer会自动拆箱为int,所以为true
        System.out.println(i == i2);  //true
        System.out.println(i == i3);  //true
        System.out.println("**************");
        System.out.println(i2 == i3);  //false
        Integer i5 = 127;//java在编译的时候,被翻译成-> Integer i5 = Integer.valueOf(127);
        Integer i6 = 127;
        System.out.println(i5 == i6);//true
        /*Integer i5 = 128;
        Integer i6 = 128;
        System.out.println(i5 == i6);//false
*/        Integer ii5 = new Integer(127);
        System.out.println(i5 == ii5); //false
        Integer i7 = new Integer(127);
        Integer i8 = new Integer(123);
        System.out.println(i7 == i8);  //false

总结一下就是如果 Integer 和int类型相比,那么会将Integer类型拆箱为int类型的然后进行数值比较,如果是 Integer i = new Integer (127);这种会创建新的 Integer对象,所以实际对比的是两个对象,基本会返回false(当然如果和int类型相比也是返回 数值比较结果)。如果 是 Integer i1 = 127,Integer i2 = 127,这种比较的话,如果小于128 会返回true,大于等于128 会返回false。

为什么会出现这样呢,上面说到 integer i = 127, 会执行装箱操作,实际上 是执行了 Integer.valueOf(127),我们看一下 valueOf函数

public static Integer valueOf(int i) {
    return  i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}

它会首先判断i的大小:如果i小于-128或者大于等于128,就创建一个Integer对象,否则执行SMALL_VALUES[i + 128]。

private static final Integer[] SMALL_VALUES = new Integer[256];

它们的值在(-128,128]这个范围内,它们会拿到SMALL_VALUES数组里面的同一个对象SMALL_VALUES[228],它们引用到了同一个Integer对象。

时间: 2024-11-05 12:34:06

Java中的拆箱和装箱的相关文章

Java的自动拆箱和装箱

Java 1.5中引入了自动装箱和拆箱机制 自动装箱:(看代码) <span style="font-family:SimSun;font-size:18px;color:#000000;">//自动装箱:把基本类型用它们所对应的引用类型包装起来,使它们具有对象的属性 Integer integer_a = 8; </span> 自动拆箱:(看代码) <span style="font-family:SimSun;font-size:18px;c

Java知多少(24)包装类、拆箱和装箱详解

虽然 Java 语言是典型的面向对象编程语言,但其中的八种基本数据类型并不支持面向对象编程,基本类型的数据不具备“对象”的特性——不携带属性.没有方法可调用. 沿用它们只是为了迎合人类根深蒂固的习惯,并的确能简单.有效地进行常规数据处理. 这种借助于非面向对象技术的做法有时也会带来不便,比如引用类型数据均继承了 Object 类的特性,要转换为 String 类型(经常有这种需要)时只要简单调用 Object 类中定义的toString()即可,而基本数据类型转换为 String 类型则要麻烦得

Java自动装/拆箱下,三目运算符的潜规则

最近发现了一个很诡异的NullPointerException,在下面这个方法抛出,一开始怎么都没想明白,dSrc即使为null,那直接赋值给distinct也没问题啊. private Doubledistinct; private void setParam(Double dSrc, boolean flag) { this.distinct = (flag) ? dSrc : 0d; } 最后才发现是Java自动拆箱的潜规则,下面我们来看看其所以然. 自动装箱/拆箱 在JDK1.5引入自动

拆箱与装箱

拆箱与装箱是一个早就接触的知识点,但是自己并没有系统的总结过,今天我们就来看一下: 一.首先介绍几个知识点: 值类型: 1. 值类型是在栈中分配内存,在声明时初始化才能使用,不能为null. 2. 值类型超出作用范围系统自动释放内存. 3. 主要由两类组成:结构,枚举(enum),结构分为以下几类: 1. 整型(Sbyte.Byte.Char.Short.Ushort.Int.Uint.Long.Ulong) 2. 浮点型(Float.Double) 3. decimal 4. bool 5. 

C#之拆箱,装箱

C#的数据类型分为三类,值类型,引用类型和指针类型.指针类型只能用于不安全模式,而值类型和引用类型通过拆箱和装箱机制可以相互转换,通过中间的object类型,所以C#的所有种类直接或间接地从object类种类派生而来. 值类型 值类型数据存储在栈中,栈用于存放固定长度的数据,分为简单类型,结构类型和枚举类型. 结构类型:把不同类型的数据组合在一起,便于使用.跟类相似,包含数据成员和函数成员的数据结构,类类型是一种引用类型.结构类型用关键字Struct定义,可以嵌套定义. 枚举类型:成员只能是整数

拆箱,装箱,枚举,结构

枚举: 1.不能定义自己的方法 2.它们不能实现接口 3.不能定义属性和索引器 4.枚举成员之间用“,”隔开 5.枚举成员如果没有赋值,那么它的第一个值默认为0 6.后面的成员取值是前一个成员取值+17.枚举成员只能赋值为整型 类与结构:1.类和结构都是创建对象的模版2.结构是值类型,类是引用类型,结构不能有析构函数3.类可以有析构函数结构不能声明默认构造函数(没有参数的构造函数)4.结构可以声明构造函数,但他们必须带参数,并且需要把所有字段都要赋值 5.在结构中初始化实例字段是错误的,在类中是

拆箱和装箱

1.拆箱和装箱,我们都知道的是 装箱:就是将值类型转换为引用类型拆箱:将引用类型转换为值类型 2.那么看下面一个例子: string str=“123”int n=Convert.ToInt32(str): string是引用类型,int为值类型.那么,此处有没有发生拆装箱呢 答案是:没有 原因:看两种类型是否发生了装箱或拆箱,要看这两种类型是否存在继承关系.有继承关系才有可能发生装箱和拆箱 3.现在,我们只知道拆装箱的定义,那么拆装箱到底给我们的应用程序带来了好处还是坏处呢? 我们可以看下面一

c# 的引用类型和值类型和数据的拆箱和装箱

c#中引用类型和值类型的区分: 一般的以calss声明的变量的类型是引用类型的,引用类型是存放到内存的堆上存放的是数据的地址.值类型是像int float 还有struct等属于值类型的数据类型,值类型的数据是存放在堆栈上的存放的数据本身. 拆箱和装箱: 我们可以用一个例子来理解装箱和拆箱的关系和作用.我们都知道小时候在村里有哪种你给他一些铝制品他可以给你溶成一个你想要的其他的铝制器件.装箱和拆箱就是这个原理.例如:你想把一种数据类型转化为另一种数据类型,int16到int32的数据类型的转化,

第十七节:易混淆的概念(静态和非静态、拆箱和装箱)

一. 静态和非静态 二. 拆箱和装箱 1 ! 作       者 : Yaopengfei(姚鹏飞) 博客地址 : http://www.cnblogs.com/yaopengfei/ 声     明1 : 本人才疏学浅,用郭德纲的话说"我是一个小学生",如有错误,欢迎讨论,请勿谩骂^_^. 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,如需代码请留下你的评论,加我QQ:604649488 (备注:评论的博客名) 原文地址:https://www.c