包装类其实就是将基本数据类型封装成类的一个属性,然后定义了一系列的方法来操作该基本类型的值
以Integer为例:
public final class Integer extends Number implements Comparable<Integer> {
...
//底层存储的数据
private final int value;
//构造器
public Integer(int value) {
this.value = value;
}
...
}
1.为什么需要包装类?
(1)Java并不是纯面向对象的语言。
Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的。
基本数据类型有它的优势:性能(效率高,节省空间)
Java中哪些语法体现了其不是纯面向对象的语言?
1.基本数据类型
2.static语法
(2)使用包装类将基本数据类型转化成对象,便于操作。
- 集合的操作
- 使用Object类型接收任意类型的数据等
- 泛型实参
这时,我们就需要将基本数据类型数据转化为对象
2.基本数据类型和包装类的对应
其中有六个都是继承自java.lang.Number类:
3.自动装箱与自动拆箱
(1)JDK1.5之前需要手动装箱与拆箱,JDK1.5之后支持自动装箱与自动拆箱
(2)装箱:基本数据类型=>包装类对象
(3)拆箱:包装类对象=>基本数据类型
public class Main {
public static void main(String[] args) {
//自动装箱
Integer total = 99;
//自定拆箱
int totalprim = total;
}
}
(4)拆箱与装箱的本质
- 装箱 valueOf()
Integer total = 99;
//执行上面那句代码的时候,系统为我们执行了:
Integer total = Integer.valueOf(99);
- 拆箱 xxxValue()
int totalprim = total;
//执行上面那句代码的时候,系统为我们执行了:
int totalprim = total.intValue();
(5)比较
1.当基本数据类型和对象类型进行比较的时候,会对包装类型进行自动拆箱
- 包装类和基本数据类型比较 本质上是基本数据类型之间比较
- 基本数据类型之间进行比较,所遵守的规则就是 自动向上转型
@Test
public void test02(){
int a = 1;
Integer b = 1;
System.out.println(a == b);//true
//自动拆箱后的基本数据类型之间进行比较,所遵守的规则就是 自动向上转型
int c = 1;
Double d = 1.0;
System.out.println(c == d);//true
}
2.包装类和包装类比较 遵循对象比较规则
对象类型用==进行比较,不是同一类型 编译直接报错
@Test
public void test03(){
Integer a = 1;
Double b = 1.0;
//System.out.println(a == b); //编译不通过
//todo 3.
// == 用于对象比较的时候,比较的是地址
// 两个对象必须有父子关系或者同一类型才能比较
}
4.自动装箱的缓存问题
1.代码演示现象
在使用自动装箱的时候,只有使用特定的包装类类型,以及一定的数值范围,获取的包装类对象是同一个
package _10_常用类.包装类;
import org.junit.Test;
public class _05_缓存问题 {
@Test
public void test01() {
int a = 1;
int b = 1;
System.out.println(a==b); //true
int c = 130;
int d = 130;
System.out.println(c == d ); //true
}
//todo
// Byte. Short. Integer Long 等都有缓存对象
// 缓存范围为-128~127
@Test
public void test02(){
Integer e = 1;
Integer f = 1;
System.out.println(e==f);//true 比较的是地址
Integer h = 130;
Integer i = 130;
System.out.println(h == i );//false 比较的是地址
}
// 仅限于装箱
@Test
public void test03(){
Integer h1 = new Integer(120);
Integer h2 = new Integer(120);
System.out.println(h1 == h2); //false
Integer a1 = Integer.valueOf("2");
Integer a2 = Integer.valueOf("2");
System.out.println(a1 == a2); //true
}
}
2.自动装箱源码解析
从前面,我们知道自动装箱,调用的是包装类的valueOf()方法
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
当自动装箱的基本数据类型在其上下限范围内,就返回缓存的对象!否则重新new 一个包装类对象!
3.IntegerCache类介绍
此类是Integer类的内部类,对于别的包装类也有自己的内部缓存类。
该缓存类定义了:
1.该数据类型的上下限取值
2.该包装类的数组 cache[],该数组装了-128到127的包装类对象
注意这个cache[] 缓存是静态常量,意味着存在于常量池中,并非堆中!
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
4.总结
在自动装箱的时候,调用静态的valueOf()方法,此方法会判断数值是否在一定范围内,如果在范围内,直接返回内部类中缓存的数组中的对象,因此获取的是同一个包装类对象;如果不在这个范围内,直接new一个包装类对象;
关于所有包装类,缓存数据范围如下:
5.包装类的使用
(1)字符串 转 基本数据类型
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
(2)字符串、基本类型 转包装类
//1.基本类型转包装类
public Integer(int value) {
this.value = value;
}
//2.字符串转包装类
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
(3)获取该数据类型的取值范围
包装类中有静态常量,可以获取该类型数值的最大最小值:MIN_VALUE、MAX_VALUE
(4)包装类的其他方法
1、Integer类型
public static String toBinaryString(int i) //把十进制转成二进制
public static String toHexString(int i) //把十进制转成十六进制
public static String toOctalString(int i) //把十进制转成八进制
2、Character类型
public static char toUpperCase(char ch) //转成大写字母
public static char toLowerCase(char ch) //转成小写字母
其他的查看相关API文档即可
3、equals
按照包装的基本数据类型的值比较
4、compareTo
按照包装的基本数据类型的值比较