1.概念

首先简单介绍一下概念性的东西:

所谓封箱:就是把基本类型封装成其所对应的包装类型;

而拆箱则恰好相反,是把包装类型转换成其所对应的基本数据类型。

如基本类型int,封箱后的包装类是Integer。

2.包装类的缓存值,equals与==

  相信,大家对equals与==一定很熟悉了吧,同样,包装类也重写了equals方法,只要两个包装类对象所包装的基本类型数据是相等的,那么,则认为两个包装类对象是相等的;

  然后,看一段简单的程序,并预测以下它的打印结果:

public class Test {
public static void main(String[] args) {
System.out.println("---------------------");
testBooleanBoxing();
System.out.println("---------------------");
testByteBoxing();
System.out.println("---------------------");
testShortBoxing();
System.out.println("---------------------");
testIntegerBoxing();
System.out.println("---------------------");
testFloatBoxing();
} public static void testFloatBoxing() {
Float float1 = 10F;
Float float2 = 10F;
Float float3 = 300F;
Float float4 = 300F;
System.out.println("float1.equals(float2) : " + float1.equals(float2));
System.out.println("float1 == float2 : " + (float1 == float2));
System.out.println("float3.equals(float4) : " + float3.equals(float4));
System.out.println("float3 == float4 : " + (float3 == float4));
} public static void testIntegerBoxing() {
Integer int1 = 10;
Integer int2 = 10;
Integer int3 = 300;
Integer int4 = 300;
System.out.println("int1.equals(int2) : " + int1.equals(int2));
System.out.println("int1 == int2 : " + (int1 == int2));
System.out.println("int3.equals(int4) : " + int3.equals(int4));
System.out.println("int3 == int4 : " + (int3 == int4));
} public static void testByteBoxing() {
Byte byte1 = -128;
Byte byte2 = -128;
Byte byte3 = 127;
Byte byte4 = 127;
System.out.println("byte1.equals(byte2) : " + byte1.equals(byte2));
System.out.println("byte1 == byte2 : " + (byte1 == byte2));
System.out.println("byte3.equals(byte4) : " + byte3.equals(byte4));
System.out.println("byte3 == byte4 : " + (byte3 == byte4));
} public static void testShortBoxing() {
Short short1 = -128;
Short short2 = -128;
Short short3 = 128;
Short short4 = 128;
System.out.println("short1.equals(short2) : " + short1.equals(short2));
System.out.println("short1 == short2 : " + (short1 == short2));
System.out.println("short3.equals(short4) : " + short3.equals(short4));
System.out.println("short3 == short4 : " + (short3 == short4));
} public static void testBooleanBoxing() {
Boolean bool1 = true;
Boolean bool2 = true;
Boolean bool3 = true;
Boolean bool4 = true;
System.out.println("bool1.equals(bool2) : " + bool1.equals(bool2));
System.out.println("bool1 == bool2 : " + (bool1 == bool2));
System.out.println("bool3.equals(bool4) : " + bool3.equals(bool4));
System.out.println("bool3 == bool4 : " + (bool3 == bool4));
}
}

然后看以下结果:

---------------------
bool1.equals(bool2) : true
bool1 == bool2 : true
bool3.equals(bool4) : true
bool3 == bool4 : true
---------------------
byte1.equals(byte2) : true
byte1 == byte2 : true
byte3.equals(byte4) : true
byte3 == byte4 : true
---------------------
short1.equals(short2) : true
short1 == short2 : true
short3.equals(short4) : true
short3 == short4 : false
---------------------
int1.equals(int2) : true
int1 == int2 : true
int3.equals(int4) : true
int3 == int4 : false
---------------------
float1.equals(float2) : true
float1 == float2 : false
float3.equals(float4) : true
float3 == float4 : false

不知道大家预测的结果和实际结果是否是相同的;

  或许有些人有疑问,不同的值对于同一包装类来说,使用 == 运算符得出的结果却是不同的,这是为什么呢?

  这就要从包装类的不可变性说起。先说以下String,因为String类的对象创建后不可改变,所以多个引用指向同一个String也不会有什么危险,因此,在编译阶段会将String常量放入字符串常量池中,当下次使用时就可以直接从字符串常量池中提取。

  而包装类和String类似,对象同样是不可变的,所以对于某些频繁使用的值,系统提供了包装类的缓存(即预先创建了经常使用的包装类对象,可以参考包装类的valueOf方法),当需要时直接从缓存中提取,而不是再创建一个新的包装类对象。这样当重复使用的时候就可以避免重复创建对象造成的资源浪费。而这些缓存的包装类的值如下:

  • boolean的所有值(true 和 false);
  • byte的所有制(-128 ~ 127);
  • char值的(0 ~ 127);
  • short值的(-128 ~ 127);
  • int值的(-128 ~ 127);
  • long值的(-128 ~ 127);

其中,浮点数类型float和double,包装类没有缓存。

如以上int类型,因为10在Integer的缓存范围内,所以

Integer int1 = 10;
Integer int2 = 10;

  两次对10的封箱使用的都是缓存中包装数值为10的Integer对象(这些对象被封装在IntegerCache类中),因此int1和int2指向的相同的对象,所以不论是 equals 还是 == ,运算的结果都是true;

  而数值300则不在缓存的范围内,因此并不是使用缓存中的对象,而是新建两个Integer对象,所以 int3 和 int4 使用 == 运算符的结果为false,其他的情况与Integer类似。

  如果要了解详细的缓存值,可查看源码中相应的Cache即可,如char值的可查看CharacterCache类,long值的可查看LongCache类;

3. 拆箱还是封箱

  在Java中 == 和 != 都可以应用于任何类型,但如果这两个二元操作符的两个操作数一个是基本数据类型,而另一个是包装类,那这是会如何操作呢?

int x = 5;
Integer y = 5;
boolean bool = (x == y);

  如果要计算 x== y,那么,是将x封箱成Integer类型与y进行比较,还是将y拆箱成int类型与x进行比较呢?

  我们看下面代码:

   public static void main(String[] args) {
int int1 = 200;
Integer int2 = 200;
if (int1 == int2) {
System.out.println("拆箱操作");
} else {
System.out.println("封箱操作");
} int int3 = 10;
Integer int4 = new Integer(10);
if (int3 == int4) {
System.out.println("拆箱操作");
} else {
System.out.println("封箱操作");
} //混合类型比较
short short1 = 200;
Integer int5 = 200;
if (short1 == int5) {
System.out.println("拆箱操作");
} else {
System.out.println("封箱操作");
}
}

返回结果如下:

拆箱操作
拆箱操作
拆箱操作

  结果已经一目了然了。当基本数据类型与包装类型进行 == 比较时,因为比较的是内存地址,所以根据结果来看,是将包装类拆箱成基本数据类型,然后对两个基本数据类型进行比较。

4. 方法中的封箱与拆箱操作

看下面的代码:

public class Test {
public static void main(String[] args) {
Test test = new Test();
int x = 10;
test.box1(x);
test.box2(x);
test.box3(x);
} public void box1(int x) {
System.out.println("调用int参数的box1方法");
} public void box1(float x) {
System.out.println("调用float参数的box1方法");
} public void box1(Integer x) {
System.out.println("调用Integer参数的box1方法");
} public void box2(float x) {
System.out.println("调用float参数的box2方法");
} public void box2(Integer x) {
System.out.println("调用Integer参数的box2方法");
} public void box3(Integer x) {
System.out.println("调用Integer参数的box3方法");
}
}

运行后,看以下结果:

调用int参数的box1方法
调用float参数的box2方法
调用Integer参数的box3方法

  结果应该不会有什么问题,重载方面的问题我会单独拿出来再说。这里要说的是,把封箱操作置后考虑(即只有当选择不到合适参数的方法时,才考虑封箱操作),主要是为了兼容以前的版本。试想:

public void method(float f) {}
public void method(Integer i) {}

  如果要调用 method(7),那么在JDK5之前的版本,因为没有自动封箱,所以会调用float参数的method方法。这是大多数人都知道的,如果JDK5后规定优先考虑封箱操作的话,那么该程序就会调用Integer参数的method方法,这对大多数人来说,都是很尴尬的,以前的那些脑海里的规则都要改变了。所以,对于新增的自动封箱特性,只能置后考虑了。

参考自:《细说Java》

【细说Java】Java封箱拆箱的一些问题的更多相关文章

  1. 1.1 JAVA装箱和拆箱以及Java Number & Math&Character 类

    JAVA装箱和拆箱 从Java SE5开始就提供了自动装箱的特性,如果要生成一个数值为10的Integer对象,只需要这样就可以了.原文链接: http://www.cnblogs.com/dolph ...

  2. Java装箱和拆箱的基本概念及使用

    Java装箱和拆箱的基本概念及使用 要理解装箱和拆箱的概念,就要理解Java数据类型 装箱:把基本类型用它们相应的引用类型包装起来,使其具有对象的性质.int包装成Integer.float包装成Fl ...

  3. Java包装类及其拆箱装箱

    Java包装类,Wrapper~由于在java中,数据类型总共可分为两大种,基本数据类型(值类型)和类类型(引用数据类型).基本类型的数据不是对象,所以对于要将数据类型作为对象来使用的情况,java提 ...

  4. Java自动装箱拆箱

    一.装箱.拆箱定义 如果一个int型量被传递到需要一个Integer对象的地方,那么,编译器将在幕后插入一个对Integer构造方法的调用,这就叫做自动装箱.而如果一个Integer对象被放到需要in ...

  5. 那些年一起踩过的坑 — java 自动装箱拆箱问题

    坑在哪里?   我们都知道Java的八种基本数据类型:int, short, long, double, byte, char, float, boolean   分别有各自对应的包装类型:Integ ...

  6. JAVA——装箱和拆箱

    Java 将某些基本数据类型自动转换为包装类型的过程称为装箱,相反自动将包装类型转换为基本数据类型的过程称为拆箱. Integer integer_1=1; //装箱 int i=integer_1; ...

  7. Java 装箱、拆箱 包装器

    先说java的基本数据类型.java基本数据类型:byte.short.int.long.float.double.char.boolean 基本数据类型的自动装箱(autoboxing).拆箱(un ...

  8. java装箱跟拆箱解析

    /** * 在jdk1.5之后,java为基本数据类型到对应的应用数据类型提供了自动拆箱装箱操作 * 不管是自动拆箱还是自动装箱都是应用数据类型有的方法,基本数据类型是没有任何方法可调用的 *从概念上 ...

  9. java自动装箱拆箱总结

    对于java1.5引入的自动装箱拆箱,之前只是知道一点点,最近在看一篇博客时发现自己对自动装箱拆箱这个特性了解的太少了,所以今天研究了下这个特性.以下是结合测试代码进行的总结. 测试代码: int a ...

随机推荐

  1. pat 1062. Talent and Virtue (25)

    难得的一次ac 题目意思直接,方法就是对virtue talent得分进行判断其归属类型,用0 1 2 3 4 表示 不合格 sage noblemen foolmen foolmen 再对序列进行排 ...

  2. PHP学习路径

    php学习大致可分为三个阶段: 第一阶段:基础知识,页面布局. 学习内容:html.div+css.js. 学习目标:div+css设计. 阶段二:php核心知识和数据库交互. 学习内容:php核心知 ...

  3. Swift: 继承

    为了在属性值改变的时候获得通知,类可以为继承的属性添加属性观察者.属性观察者可以添加到任何属性上,不管这个属性原来是存储属性还是计算属性. Swift中的类没有一个统一的基类. 为了讲明白继承,我们先 ...

  4. Macos Coco2d-x Android开发

    1. 在装好环境 2. cocos new [-h] [-p PACKAGE_NAME] -l {cpp,lua,js} [-d DIRECTORY] [-t TEMPLATE_NAME] [--io ...

  5. 非空验证(源代码Java版)

    import java.util.Map; /** * 非空验证工具类 */ public class UntilEmpty { /** * @see: 验证string类型的是否为空 */ publ ...

  6. Volley的基本使用(转)

    Volley是Google在2003年的I/O大会上推出的通信框架,结合了AsyncHttpClient和Universal-Image-Loader的优点——简化了http的使用 + 异步加载图片的 ...

  7. UITextField控件处理键盘弹出时遮住输入框的问题

    原文连接: http://www.devdiv.com/thread-70159-1-1.html 实现以下三个方法,如果弹出的键盘会遮住输入框 ,整体的界面会向上移动,这样就不会遮住输入框了.自己增 ...

  8. crud的意识

    CRUD说的就是增查改删C:Create 增加对应CREATE TBL ...: ADD TBL IN (...) VALUES (...)R:Retrieve查询SELECT * from TBLU ...

  9. C# static 干货全解析

    讲解顺序 背景 静态字段 静态函数 静态方法 疑问解答 背景 static来源 在编写类的时候,有时候需要类里面的某个成员具有唯一性,也就是,对所有的对象都保持只有一个的状态.比如创建个人信息,我们都 ...

  10. JavaScript--赋值表达式(typeof-delete-void)

    typeof运算符 typeof是一个一元运算符,操作数可以使任意类型,返回值为操作数类型的一个字符串 一.数字类型,如typeof(1),返回的值就是number.当然这个是常规数字,对于非常规的数 ...