JAVA基本类型和包装类的装箱与拆箱
2017-10-27 10:29
211 查看
JAVA的包装类
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的,这在实际使用时存在很多的不便,为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行代表,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class),有些地方也翻译为外覆类或数据类型类,如下表所示:基本类型 | 大小 | 包装器类型 |
---|---|---|
boolean | / | Boolean |
char | 16bit | Character |
byte | 8bit | Byte |
short | 16bit | Short |
int | 32bit | Integer |
long | 64bit | Long |
float | 32bit | Float |
double | 64bit | Double |
void | / | Void |
提供一种机制,将基本值“包装”到对象中,从而使基本值能够包含在为对象而保留的操作中,比如添加到Collections 中,或者从带对象返回值的方法中返回。注意,java5增加了自动装箱和拆箱,程序员过去需手工执行的许多包装操作,现在可以由java自动处理了。
为基本值提供分类功能。这些功能大多数于各种转换有关:在基本值和String对象间相互转换,在基本值和String对象之间按不同基数转换,如二进制、八进制和十六进制。
包装类共同的方法
带有基本值参数并创建包装类对象的构造函数。如利用Integer包装类创建对象,Integer obj=new Integer(145);
带有
字符串参数并创建包装类对象的构造函数.如:new Integer(“-45.36”);
可生成对象基本值的
typeValue方法,如:obj.intValue();
将字符串转换为基本值的
parseType方法,如:Integer.parseInt(args[0]);
生成哈稀表代码的
hashCode方法,如:obj.hasCode();
对同一个类的两个对象进行比较的
equals()方法,如:obj1.eauqls(obj2);
生成字符串表示法的
toString()方法,如:obj.toString().
装箱和拆箱
自动装箱和拆箱问题是Java中一个老生常谈的问题了,今天就来一些看一下装箱和拆箱中的若干问题。本文先讲述装箱和拆箱最基本的东西,再来看一下面试笔试中经常遇到的与装箱、拆箱相关的问题。定义
在前面的文章中提到,Java为每种基本数据类型都提供了对应的包装器类型,至于为什么会为每种基本数据类型提供包装器类型在此不进行阐述,有兴趣的朋友可以查阅相关资料。在Java SE5之前,如果要生成一个数值为10的Integer对象,必须这样进行:1 | Integer i = new Integer(100); |
1 | int i = 100; |
那什么是拆箱呢?顾名思义,跟装箱对应,就是自动将包装器类型转换为基本数据类型:
12 | Integer i = 10; //装箱int index = i; //拆箱 |
注意:
12 | Integer test = null;int f = test.intValue(); |
实现机制
我们就以Interger类为例,下面看一段代码:1234 | public static void main(String[] args){ Integer i = 10; //装箱 int index = i; //拆箱} |
从反编译得到的字节码内容可以看出,在装箱的时候自动调用的是Integer的
valueOf(int)方法。而在拆箱的时候自动调用的是Integer的
intValue方法。
其他的也类似,比如Double、Character,不相信的朋友可以自己手动尝试一下。
因此可以用一句话总结装箱和拆箱的实现过程:
装箱过程是通过调用包装器的valueOf方法实现的,而拆箱过程是通过调用包装器的xxxValue方法实现的。(xxx代表对应的基本数据类型)。
面试问题
虽然大多数人对装箱和拆箱的概念都清楚,但是在面试和笔试中遇到了与装箱和拆箱的问题却不一定会答得上来。下面列举一些常见的与装箱/拆箱有关的面试题,建议先自己尝试编译看源码做做。下面这段代码的输出结果是什么?
1234567891011 | public class Main { public static void main(String[] args) { Integer i1 = 100; Integer i2 = 100; Integer i3 = 200; Integer i4 = 200; System.out.println(i1==i2); System.out.println(i3==i4); }} |
基本类型 | == | equals |
---|---|---|
字符串变量 | 对象在内存中的首地址 | 字符串内容 |
非字符串变量 | 对象在内存中的首地址 | 对象在内存中的首地址 |
基本类型 | 值 | 不可用 |
包装类 | 地址 | 内容 |
true
false
为什么会出现这样的结果?输出结果表明 i1 和 i2 指向的是同一个对象,而 i3 和 i4 指向的是不同的对象。此时只需一看源码便知究竟,下面这段代码是Integer的
valueOf方法的具体实现:
123456 | public static Integer valueOf(int i) { if(i >= -128 && i <= IntegerCache.high) return IntegerCache.cache[i + 128]; else return new Integer(i); } |
上面的代码中 i1 和 i2 的数值为100,因此会直接从cache中取已经存在的对象,所以 i1 和 i2 指向的是同一个对象,而 i3 和 i4 则是分别指向不同的对象。
下面这段代码的输出结果是什么?
1234567891011 | public class Main { public static void main(String[] args) { Double i1 = 100.0; Double i2 = 100.0; Double i3 = 200.0; Double i4 = 200.0; System.out.println(i1==i2); System.out.println(i3==i4); }} |
false
false
至于具体为什么,读者可以去查看Double类的
valueOf的实现。
在这里只解释一下为什么Double类的valueOf方法会采用与Integer类的valueOf方法不同的实现。很简单:在某个范围内的整型数值的个数是有限的,而浮点数却不是。
注意,Integer、Short、Byte、Character、Long这几个类的valueOf方法的实现是类似的,Double、Float的valueOf方法的实现是类似的。
下面这段代码的输出结果是什么?
1234567891011 | public class Main { public static void main(String[] args) { Boolean i1 = false; Boolean i2 = false; Boolean i3 = true; Boolean i4 = true; System.out.println(i1==i2); System.out.println(i3==i4); }} |
true
true
至于为什么是这个结果,同样地,看了Boolean类的源码也会一目了然。下面是Boolean的valueOf方法的具体实现:
123 | public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } |
1234567891011 | /** * The {@code Boolean} object corresponding to the primitive * value {@code true}. */ public static final Boolean TRUE = new Boolean(true); /** * The {@code Boolean} object corresponding to the primitive * value {@code false}. */ public static final Boolean FALSE = new Boolean(false); |
当然,这个题目属于比较宽泛类型的。但是要点一定要答上,我总结一下主要有以下这两点区别:
1)第一种方式不会触发自动装箱的过程;而第二种方式会触发;
2)在执行效率和资源占用上的区别。第二种方式的执行效率和资源占用在一般性情况下要优于第一种情况(注意这并不是绝对的)。
下面这段代码的输出结果是什么?
1234567891011121314151617181920 | public class Main { public static void main(String[] args) { Integer a = 1; Integer b = 2; Integer c = 3; Integer d = 3; Integer e = 321; Integer f = 321; Long g = 3L; Long h = 2L; System.out.println(c==d); System.out.println(e==f); System.out.println(c==(a+b)); System.out.println(c.equals(a+b)); System.out.println(g==(a+b)); System.out.println(g.equals(a+b)); System.out.println(g.equals(a+h)); }} |
1234567 | truefalsetruetruetruefalsetrue |
原文地址http://alexyyek.github.io/2014/12/29/wrapperClass/
【四川乐山程序员联盟,欢迎大家加群相互交流学习5 7 1 8 1 4 7 4 3】
相关文章推荐
- java基础--包装类之基本数据类型的装箱和拆箱
- Java基础知识强化66:基本类型包装类之JDK5新特性自动装箱和拆箱
- 01 Java基本数据类型、包装类、装箱拆箱、parseXxx()、String.valueOf()
- java语言基础(59)——jdk5自动装箱和拆箱(基本数据类型与包装类之间的转换)
- java基本数据类型与字符串之间的转换(基本数据类型、对象封装类、自动装箱、自动拆箱)
- 黑马程序员——JAVA基础之基本数据类型包装类和1.5JDK新特性装箱
- 基本数据类型对象包装类和自动装箱自动拆箱技术
- Java八种基本数据类型的大小,以及封装类,自动装箱/拆箱的用法?
- 加强eclipse的使用技巧。可变参数。基本数据类型自动装箱和拆箱。枚举。反射。数组反射的应用。ArrayList和HashSet。JavaBean
- Java中基本数据类型的自动拆箱和装箱
- java类型自动装箱拆箱和字符串与基本类型的装换
- java基本类型自动装箱与拆箱
- JAVA1.5新特性----基本数据类型的自动拆箱与装箱
- Java基本数据类型的大小,他们的封装类以及自动拆箱和装箱
- Java高新技术【1】 (静态导入-可变参数-增强for循环-基本数据类型的自动拆箱与装箱)
- JAVA——基本数据类型对象包装类/自动装箱
- 基本数据类型对象包装类和自动装箱自动拆箱技术
- JAVA进阶之旅(一)——增强for循环,基本数据类型的自动拆箱与装箱,享元设计模式,枚举的概述,枚举的应用,枚举的构造方法,枚举的抽象方法
- Java中的基本类型与封装类型以及自动装箱、拆箱
- JAVA进阶学习-java基本类型装箱、拆箱