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》

最新文章

  1. JavaScript 入门教程四 语言基础【3】
  2. POJ 3276 Face The Right Way 反转
  3. Toad快速入门
  4. 【Maven】Eclipse 使用Maven创建Java Web项目
  5. Dreamweaver8 查找和替换窗口不见了解决办法
  6. JSValidation客户端验证框架
  7. unity, OnTriggerStay/OnTriggerStay2D not called every fixedUpdate frame
  8. 了解struts2 action的一些原理
  9. curl 查看网站连接情况
  10. leetcode:Longest Palindromic Substring(求最大的回文字符串)
  11. 【JS】<c:foreach>用法
  12. [Effective C++ --026]尽可能延后变量定义式的出现时间
  13. Android JNI入门第三篇——jni头文件分析
  14. android优化原理
  15. connect函数的用法
  16. cookie的增删改查函数
  17. C++判断字符串是否为空的一个小问题
  18. centos7下root密码丢失解决方案
  19. Java 面向对象 知识点基础浅谈
  20. 3.git 分支操作

热门文章

  1. Mono For Android离线激活
  2. android:Adb connection Error:远程主机强迫关闭了一个现有的连接
  3. 搜搜(www.soso.com),I 老虎油!
  4. java内存不足
  5. Windows下Android Studio长时间停留在Building "Project Name" Gradle project info画面的解决方法
  6. uva 10934 Dropping water balloons(转载)
  7. codevs 4909 寂寞的堆(写的好丑0.0)
  8. PHP 关于文件操作的简单介绍
  9. 七.生成n位随机字符串
  10. 1.Weblogic通Eclipse调试配置(Weblogic同Eclipse调试配置技术)