Java出道之时,自诩为“纯面向对象的语言”,意思是之前的所谓“面向对象语言”不纯。
但是,有人指责Java也不纯——8种基本类型并非类类型。为此,Java为他们提供可对应的类类型,是为“包装类”。

包装类

Java的八种基本数据类型用起来很方便,但不支持面向对象的编程机制,不属于Object继承体系,没有成员方法可调用。某些场合下,只能使用对象类型,不能使用基本类型,因此基本类型需要对应的包装类。

比如集合的定义:List<Integer> list;
写为List<int> list;就错了

Java提供了基本类型对应的包装类(Wrapper Class):

包装类一般就是把基本类型的首字母小写变为大写,但是int和char除外,它们的包装类要用全称。
下表中将int和char的写法加粗。

基本类型

包装类

byte

Byte

int

Integer

short

Short

long

Long

float

Float

double

Double

boolean

Boolean

char

Character

另有一种说法,说Java中有9种基本类型,还要加一个void,其包装类是Void,但这种说法没有被普遍接受。

装箱和拆箱的概念

基本类型→(转为)→包装类,是为装箱
包装类→(转为)→基本类型,是为拆箱

java基本类型的包装类 java基础类型包装类_System

java基本类型的包装类 java基础类型包装类_java基本类型的包装类_02

JDK 1.5开始就提供了自动装箱、自动拆箱功能。借助该功能,开发者可以把基本类型当做对象使用,也可以把包装类的实例当做基本类型变量使用。

public class Test包装类 {
    public static void main(String[] args) {
        int a1 = 1000;// 定义基本类型
        Integer objA = a1; // 自动装箱:Integer←int
        int a2 = objA; // 自动拆箱:int←Integer
        System.out.println(a2);
    }
}
public class Test包装类 {
    public static void main(String[] args) {
        int a1 = 1000;// 定义基本类型
        Integer objA = a1; // 自动装箱:Integer←int
        int a2 = objA; // 自动拆箱:int←Integer
        System.out.println(a2);
    }
}

上述代码的解析:
| | int a1 = 1000; | | |
| -------- | -------------------------- | ----------- | -------------------------------- |
| 自动装箱 | Integer objA =a1; | Integer←int | 本质上调用了Integer.valueOf(...) |
| 自动拆箱 | int a2 = objA; | int←Integer | 本质上调用了objA.intValue() |

包装类可以通过new实例化来构造
除Character类外,其它的包装类都有parseXxx方法:字符串→基本数据类型
包装类有valueOf方法:字符串→包装类对象

示例代码(比较枯燥,瞅一眼就行):

public class Test构造包装类 {
    public static void main(String[] args) {
        构造包装类();
        parseXxx_str_to_基本类型();
        valueOf_str_to_Wrapper();
    }
    static void 构造包装类() {
        System.out.println("---new 包装类---");
        Boolean objBool = new Boolean(true);
        Character objChar = new Character('X');
        Byte objByte = new Byte((byte) 10);
        Short objS = new Short((short) 50);
        Integer objInt = new Integer(100);
        Long objLong = new Long(1000);
        Float objF = new Float(3.14);
        Double objD = new Double(3.1415);
        System.out.println(objBool);
        System.out.println(objChar);
        System.out.println(objByte);
        System.out.println(objS);
        System.out.println(objInt);
        System.out.println(objLong);
        System.out.println(objF);
        System.out.println(objD);
    }
    static void parseXxx_str_to_基本类型() {
        String str = "123";
        System.out.println("---除Character类外,包装类都有parseXxx方法");
        System.out.println("---parseXxx:字符串→基本数据类型值");
        byte b = Byte.parseByte(str);
        short s = Short.parseShort(str);
        int i = Integer.parseInt(str);
        long l = Long.parseLong(str);
        float f = Float.parseFloat(str);
        double d = Double.parseDouble(str);
        boolean bl = Boolean.parseBoolean("TruE");
        System.out.println(i);
        System.out.println(s);
        System.out.println(b);
        System.out.println(l);
        System.out.println(f);
        System.out.println(d);
        System.out.println(bl);
    }
    static void valueOf_str_to_Wrapper() {
        String str = "123";
        System.out.println("---valueOf方法:字符串→包装类对象");
        Byte objByte = Byte.valueOf(str);
        Short objShort = Short.valueOf(str);
        Integer objInt = Integer.valueOf(str);
        Long objLong = Long.valueOf(str);
        Float objF = Float.valueOf(str);
        Double objD = Double.valueOf(str);
        Boolean objB = Boolean.valueOf("true");
        Character obkChar = Character.valueOf('C');
        System.out.println(objByte);
        System.out.println(objShort);
        System.out.println(objInt);
        System.out.println(objLong);
        System.out.println(objF);
        System.out.println(objD);
        System.out.println(obkChar);
        System.out.println(objB);
    }
}
public class Test构造包装类 {
    public static void main(String[] args) {
        构造包装类();
        parseXxx_str_to_基本类型();
        valueOf_str_to_Wrapper();
    }
    static void 构造包装类() {
        System.out.println("---new 包装类---");
        Boolean objBool = new Boolean(true);
        Character objChar = new Character('X');
        Byte objByte = new Byte((byte) 10);
        Short objS = new Short((short) 50);
        Integer objInt = new Integer(100);
        Long objLong = new Long(1000);
        Float objF = new Float(3.14);
        Double objD = new Double(3.1415);
        System.out.println(objBool);
        System.out.println(objChar);
        System.out.println(objByte);
        System.out.println(objS);
        System.out.println(objInt);
        System.out.println(objLong);
        System.out.println(objF);
        System.out.println(objD);
    }
    static void parseXxx_str_to_基本类型() {
        String str = "123";
        System.out.println("---除Character类外,包装类都有parseXxx方法");
        System.out.println("---parseXxx:字符串→基本数据类型值");
        byte b = Byte.parseByte(str);
        short s = Short.parseShort(str);
        int i = Integer.parseInt(str);
        long l = Long.parseLong(str);
        float f = Float.parseFloat(str);
        double d = Double.parseDouble(str);
        boolean bl = Boolean.parseBoolean("TruE");
        System.out.println(i);
        System.out.println(s);
        System.out.println(b);
        System.out.println(l);
        System.out.println(f);
        System.out.println(d);
        System.out.println(bl);
    }
    static void valueOf_str_to_Wrapper() {
        String str = "123";
        System.out.println("---valueOf方法:字符串→包装类对象");
        Byte objByte = Byte.valueOf(str);
        Short objShort = Short.valueOf(str);
        Integer objInt = Integer.valueOf(str);
        Long objLong = Long.valueOf(str);
        Float objF = Float.valueOf(str);
        Double objD = Double.valueOf(str);
        Boolean objB = Boolean.valueOf("true");
        Character obkChar = Character.valueOf('C');
        System.out.println(objByte);
        System.out.println(objShort);
        System.out.println(objInt);
        System.out.println(objLong);
        System.out.println(objF);
        System.out.println(objD);
        System.out.println(obkChar);
        System.out.println(objB);
    }
}

Java中100等于100,1000不等于1000

public class Java1000 {
    public static void main(String[] args) {
        Integer a1 = 100;
        Integer a2 = 100;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));

        a1 = 1000;
        a2 = 1000;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));
    }
}
public class Java1000 {
    public static void main(String[] args) {
        Integer a1 = 100;
        Integer a2 = 100;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));

        a1 = 1000;
        a2 = 1000;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));
    }
}

100==100:true
1000==1000:false


原因:JDK源码的Integer类中,将-128~127做了缓存处理。
看看这段缓存:

package java.lang;
……
public final class Integer extends Number implements Comparable<Integer> {
……
    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;
            ……
            high = h;
            ……
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
        private IntegerCache() {}
    }
    ……
}
package java.lang;
……
public final class Integer extends Number implements Comparable<Integer> {
……
    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;
            ……
            high = h;
            ……
            // range [-128, 127] must be interned (JLS7 5.1.7)
            assert IntegerCache.high >= 127;
        }
        private IntegerCache() {}
    }
    ……
}

改改这段缓存:(看懂大概即可)

import java.lang.reflect.Field;
import java.util.Arrays;
public class TestInteger {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        // 说明:IntegerCache是Integer中的一个内部类
        // 源码:private static class IntegerCache{...}
        // 1.取出Integer中定义的内部类(包括公共、私有、保护)
        Class<?>[] classes = Integer.class.getDeclaredClasses();
        System.out.println("Class数组:" + Arrays.toString(classes));
        Class<?> classCache = classes[0];
        System.out.println("IntegerCache:" + classCache);
        // 2.取成员变量:cache
        // 源码:static final Integer cache[];
        Field fieldCache = classCache.getDeclaredField("cache");
        System.out.println("Integer cache[]:" + fieldCache);
        fieldCache.setAccessible(true);
        // 3.取出cache的值
        // field.get(obj):返回指定对象上由此Field表示的字段的值
        Integer[] newCache = (Integer[]) fieldCache.get(classCache);
        System.out.println("Integer[]:" + Arrays.toString(newCache));
        // 0 : -128
        // 1 : -127
        // 2 : -126
        // ...
        // 127 : -1
        // 128 : 0
        // 129 : 1
        // 130 : 2
        // 131 : 3
        // 132 : 4
        // 133 : 5
        newCache[132] = newCache[133];
        int a = 2;
        int b = a + a;
        // public PrintStream printf(String format, Object ... args)
        // 用的是Object类型,取包装类
        System.out.println("println:" + a + "+" + a + "=" + b); // 2+2=4
        System.out.printf("printf:%d + %d = %d\n", a, a, b); // 2+2=5
        newCache[132] = 1999;
        System.out.println("println:b = " + b);// println:正常的4
        System.out.printf("printf:b = %d", b);// printf:新值1999
    }
}
import java.lang.reflect.Field;
import java.util.Arrays;
public class TestInteger {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        // 说明:IntegerCache是Integer中的一个内部类
        // 源码:private static class IntegerCache{...}
        // 1.取出Integer中定义的内部类(包括公共、私有、保护)
        Class<?>[] classes = Integer.class.getDeclaredClasses();
        System.out.println("Class数组:" + Arrays.toString(classes));
        Class<?> classCache = classes[0];
        System.out.println("IntegerCache:" + classCache);
        // 2.取成员变量:cache
        // 源码:static final Integer cache[];
        Field fieldCache = classCache.getDeclaredField("cache");
        System.out.println("Integer cache[]:" + fieldCache);
        fieldCache.setAccessible(true);
        // 3.取出cache的值
        // field.get(obj):返回指定对象上由此Field表示的字段的值
        Integer[] newCache = (Integer[]) fieldCache.get(classCache);
        System.out.println("Integer[]:" + Arrays.toString(newCache));
        // 0 : -128
        // 1 : -127
        // 2 : -126
        // ...
        // 127 : -1
        // 128 : 0
        // 129 : 1
        // 130 : 2
        // 131 : 3
        // 132 : 4
        // 133 : 5
        newCache[132] = newCache[133];
        int a = 2;
        int b = a + a;
        // public PrintStream printf(String format, Object ... args)
        // 用的是Object类型,取包装类
        System.out.println("println:" + a + "+" + a + "=" + b); // 2+2=4
        System.out.printf("printf:%d + %d = %d\n", a, a, b); // 2+2=5
        newCache[132] = 1999;
        System.out.println("println:b = " + b);// println:正常的4
        System.out.printf("printf:b = %d", b);// printf:新值1999
    }
}

为什么System.out.printf的结果都是我们修改的值呢?可以推测,printf一定是到缓存中去取值了。

看看printf的源码:

public PrintStream printf(String format, Object ... args)
public PrintStream printf(String format, Object ... args)

第二个参数是Object类型的(还是个可变参数),包装类是Object的子类,这里正是用的多态,用Object代表包装类的对象,取的正是Integer中的值,在-128~127范围内,取的正是缓存里的值。

最大值和最小值

通过包装类,我们可以取出数值类型的最大值和最小值,这些值在范围判断的时候很重要,但是非天才是记不住的,包装类可以帮我们快速找出来。

public class MAX_MIN {
    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);
        System.out.println(Long.MAX_VALUE);
        System.out.println(Long.MIN_VALUE);
        System.out.println(Double.MAX_VALUE);
        System.out.println(Double.MIN_VALUE);
    }
}
public class MAX_MIN {
    public static void main(String[] args) {
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);
        System.out.println(Long.MAX_VALUE);
        System.out.println(Long.MIN_VALUE);
        System.out.println(Double.MAX_VALUE);
        System.out.println(Double.MIN_VALUE);
    }
}

2147483647
-2147483648
9223372036854775807
-9223372036854775808
1.7976931348623157E308
4.9E-324

*Java7增加的包装类功能:compare比较值的大小

public class TestIntegercompare {
    public static void main(String[] args) {
        Integer a1 = 100;
        Integer a2 = 100;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));// FALSE

        a1 = 1000;
        a2 = 1000;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));// FALSE

        // 包装类.compare方法:比较值的大小(大于:1/等于:0/小于:-1)
        System.out.println(a1 + "==" + a2 + ":" + Integer.compare(a1, a2));
        System.out.println("1 VS 2 : " + Integer.compare(1, 2));
        System.out.println("2 VS 1 : " + Integer.compare(2, 1));
        System.out.println("1 VS 1 : " + Integer.compare(1, 1));
    }
}
public class TestIntegercompare {
    public static void main(String[] args) {
        Integer a1 = 100;
        Integer a2 = 100;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));// FALSE

        a1 = 1000;
        a2 = 1000;
        System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));// FALSE

        // 包装类.compare方法:比较值的大小(大于:1/等于:0/小于:-1)
        System.out.println(a1 + "==" + a2 + ":" + Integer.compare(a1, a2));
        System.out.println("1 VS 2 : " + Integer.compare(1, 2));
        System.out.println("2 VS 1 : " + Integer.compare(2, 1));
        System.out.println("1 VS 1 : " + Integer.compare(1, 1));
    }
}

*Java8增强的包装类,主要是支持无符号运算。

无符号数的最高位不再被当做符号位(不支持负数,最小值为0)

public class Java8Wapper {
    public static void main(String[] args) {
        byte b = -1;
        int unsignedInt = Byte.toUnsignedInt(b);
        System.out.println(unsignedInt);

        long unsignedLong = Byte.toUnsignedLong(b);
        System.out.println(unsignedLong);
    }
}
public class Java8Wapper {
    public static void main(String[] args) {
        byte b = -1;
        int unsignedInt = Byte.toUnsignedInt(b);
        System.out.println(unsignedInt);

        long unsignedLong = Byte.toUnsignedLong(b);
        System.out.println(unsignedLong);
    }
}

255
255