针对八种基本数据类型相应的引用类型——包装类。包装类有类的特点,可以调用类中的方法。
基本数据类型 | 包装类 | 包装类的父类 |
boolean | Boolean | Object |
char | Character | Object |
byte | Byte | Number(Number的父类是 Object) |
short | Short | |
int | Integer | |
long | Long | |
float | Float | |
double | Double |
继承体系图如下:
包装类和基本数据的转换
- jdk5 前是手动装箱和拆箱的方式,装箱:基本类型 -> 包装类 。反之,称为拆箱。
- jdk5以后(含 jdk5)就是自动装箱和拆箱
- 自动装箱底层调用的是 valueOf 方法,比如 Integer.valueOf()
以下以 int 和 Integer 为例(其他包装类类似)
public class Test {
public static void main(String[] args) {
// jdk5 以前
// 手动装箱:int -> Integer
int n1 = 100;
Integer integer1 = new Integer(n1); // 方式一
Integer integer2 = Integer.valueOf(n1); // 方式二
// 手动拆箱:Integer -> int
int n2 = integer1.intValue();
// jdk5 以后
// 自动装箱: int -> Integer
Integer integer3 = n1; // 底层调用的还是 Interger.valueOf 方法,可通过 debug 验证
// 自动拆箱: Integer -> int
int n3 = integer2; // 底层调用的是 intValue 方法
}
}
练习题:以下代码输出什么?
Object obj = true ? new Integer(1) : new Double(2.0);
/*
* 输出 1.0
* 原因:
* 1、三元运算符是一个整体,运算结果会提升到式子中的最高精度,在本题中最高精度是 double
* 2、obj 的运行类型是 Integer 对象,所以根据动态绑定机制,输出 obj 时调用的是 Integer 中的 toString 方法,所以输出的是 obj 的值
* 3、obj = true 只有一个等号,是赋值,所以结果为真
*/
System.out.println(obj); // 1.0
System.out.println(obj instanceof Double); // true
System.out.println(obj instanceof Integer); // false
// 加入题目把 Double 换成 Float , 这个三元运算符的式子最高精度就是 Float ,即 obj1 的精度就是 Float
Object obj1 = true ? new Integer(1) : new Float(2.0);
System.out.println(obj1 instanceof Float); // true
System.out.println(obj1 instanceof Integer); // false
包装类和 String 类的转换
以 Integer 为例(其他类类似)
public class Test {
public static void main(String[] args) {
// 包装类 ——> String 类
Integer i = 100; // 自动装箱
// 方式一
String str1 = i + "";
// 方式二
String str2 = i.toString();
// 方式三
String str3 = String.valueOf(i);
// String 类 ——> 包装类
String str4 = "123";
Integer i1 = new Integer(str4);
// parseInt 返回的是 int 类型,但是因为自动装箱,所以可以直接赋值给 i2
Integer i2 = Integer.parseInt(str4);
}
}
包装类常用的方法(一小部分)
- Integer.MIN_VALUE :Integer 中的最小值
- Integer.MAX_VALUE :Integer 中的最大值
- Character.isDigit('a') :判断是不是数字
- Character.isLetter('a') :判断是不是字母
- Character.isUpperCase('a') :判断是不是大写
- Character.isLowerCase('a') :判断是不是小写
- Character.isWhitespace('a') :判断是不是空格
- Character.toUpperCase('a') :转成大写
- Character.toLowerCase('A') :转成小写
Integer 的经典面试题
public class Test {
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
/*
* i 和 j 都是 new 出来的对象,是引用类型
* 而 == 号比较引用类型时比较的是对象的地址
* 因为 i 和 j 不是同一个对象,所以地址也不一样,因此返回 false
*/
System.out.println(i == j); // false
/*
* Integer.valueOf 底层源码 -128 to 127
* 根据其他源码可知 IntegerCache.low = -128 ,IntegerCache.high = 127
* 即如果 i 的值在 -128 ~ 127 这个范围里就不会创建一个新的对象
* 而是返回 cache 数组里的圆,即返回对应的 i 值
* IntegerCache.cache 是一个数组,里面存储了 -128 到 127 的值
* 超出这个范围将会 new Integer(i)
*
* public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
*
* 而 1 没有超过范围,所以自动装箱调用 Integer.valueOf() 方法返回的是同一个对象
* 输出结果为 true
*/
Integer m = 1; // 自动装箱,底层调用 Integer.valueOf() 方法
Integer n = 1; // 自动装箱,底层调用 Integer.valueOf() 方法
System.out.println(m == n); // true
/*
* 由于 x 和 y 的值超过了 127
* 所以自动装箱时底层调用的 Integer.valueOf() 方法没有满足源码里的 if 判断
* 所以返回的都是 new Integer(128)
* 即: Integer x = new Integer(128); Integer y = new Integer(128);
* 此时 x 和 y 不是同一个对象,返回 false
*/
Integer x = 128;
Integer y = 128;
System.out.println(x == y); // false
Integer p = 127;
int q = 127;
// 只要比较的两个值中有一个是基本数据类型,则 == 比较的就是值是否相等
System.out.println(p == q); // true
// 只要比较的两个值中有一个是基本数据类型,则 == 比较的就是值是否相等
// 12.0 和 12 的值相等,所以输出 true
Integer n1 = new Integer(12);
double d = 12.0;
System.out.println(n1 == d); // true
}
}