包装类介绍 Java 语言是一个面向对象的编程语言,但是 Java 中的基本数据类型却不是面向对象的,但是我们在实际使用中经常需要将基本数据类型转换成对象,便于操作,比如,集合的操作中,这时,我们就需要将基本类型数据转化成对象,所以就出现了包装类。 基本数据类型有 8 个,对应的包装类也是 8 个,如果下图所示
基本数据类型 包装类 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean
包装类的继承关系
包装类的基本操作 8 个包装类都带有自己对应的构造方法,java 中的包装类提供了将原始数据类型转换为对象,以及将对象转换为原始数据类型的机制。这里举例说明下这个过程
基本数据类型 —> 包装类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 import org.junit.Test;class Order { boolean isMale; Boolean isFemale; } public class WrapperTest { @Test public void test1 () { Integer in1 = new Integer (10 ); System.out.println(in1.toString()); Integer in2 = new Integer ("123" ); System.out.println(in2.toString()); Float f1 = new Float (12.3f ); Float f2 = new Float ("12.3" ); System.out.println(f1); System.out.println(f2); Boolean b1 = new Boolean (true ); Boolean b2 = new Boolean ("true" ); Boolean b3 = new Boolean ("true123" ); System.out.println(b3); Order order = new Order (); System.out.println(order.isMale); System.out.println(order.isFemale); } }
包装类 —> 基本数据类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import org.junit.Test;public class WrapperTest { @Test public void test2 () { Integer in1 = new Integer (12 ); int i1 = in1.intValue(); System.out.println(i1 + 1 ); Float f1 = new Float (12.3 ); float f2 = f1.floatValue(); System.out.println(f2); } }
自动装箱与自动拆箱 在 JDK1.5 版本之后新增了,自动装箱与自动拆箱功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import org.junit.Test;public class WrapperTest { @Test public void test3 () { Integer in2 = 10 ; Boolean b2 = true ; int num3 = in2; } }
基本数据类型 / 包装类 —> String 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import org.junit.Test;public class WrapperTest { @Test public void test4 () { int num1 = 10 ; String str1 = num1 + "" ; float f1 = 12.3f ; String str2 = String.valueOf(f1); System.out.println(str2); Double d1 = 12.4 ; String str3 = String.valueOf(d1); System.out.println(str3); } }
String 类型 —> 基本数据类型、包装类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import org.junit.Test;public class WrapperTest { @Test public void test5 () { String str1 = "123" ; int num1 = Integer.parseInt(str1); System.out.println(num1 + 1 ); String str2 = "true" ; boolean b1 = Boolean.parseBoolean(str2); System.out.println(b1); } }
包装类的缓存机制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import org.junit.Test;public class WrapperTest { @Test public void test6 () { Integer i = new Integer (1 ); Integer j = new Integer (1 ); System.out.println(i == j); Integer m = 1 ; Integer n = 1 ; System.out.println(m == n); Integer x = 128 ; Integer y = 128 ; System.out.println(x == y); } }
静态的内部类是在整个 Integer 加载的时候就已经加载完成了,以下代码初始化了一个 Integer 类型的叫 cache 的数组,取值范围是[-128, 127]。缓存机制的作用就是提前实例化相应范围数值的包装类对象,只要创建处于缓存范围的对象,就使用已实例好的对象。从而避免重复创建多个相同的包装类对象,提高了使用效率。如果我们用的对象范围在[-128, 127]之内,就直接去静态区找对应的对象,如果用的对象的范围超过了这个范围,会帮我们创建一个新的 Integer 对象,其实下面的源代码就是这个意思
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 private static class IntegerCache { static final int low = -128 ; static final int high; static final Integer cache[]; static { 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 ); h = Math.min(i, Integer.MAX_VALUE - (-low) -1 ); } catch ( NumberFormatException nfe) { } } high = h; cache = new Integer [(high - low) + 1 ]; int j = low; for (int k = 0 ; k < cache.length; k++) cache[k] = new Integer (j++); assert IntegerCache.high >= 127 ; } private IntegerCache () {} }
1 2 3 4 5 public static Integer valueOf (int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer (i); }
通过分析源码我们可以发现,只有 double 和 float 的自动装箱代码没有使用缓存,每次都是 new 新的对象,其它的 6 种基本类型都使用了缓存策略。 使用缓存策略是因为,缓存的这些对象都是经常使用到的(如字符、-128至127之间的数字),防止每次自动装箱都创建一次对象的实例。
包装类和基本数据类型的区别 包装类的默认值是 null,而基本数据类型是对应的默认值(比如整型默认值是0,浮点型默认值是0.0)
基本数据类型是把值保存在栈内存里,包装类是把对象放在堆中,然后通过对象的引用来调用他们
基本数据类型变量空间里面存储的是值,传递的也是值,一个改变,另外一个不变,而包装类属于引用数据类型,变量空间存储的是地址(引用),传递的也是引用,一个变,另外一个跟着变。
操作总结
基本数据类型和包装类有了自动拆箱装箱,上图主要关注和 String 类型的转换即可
练习题 练习题1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import org.junit.Test;public class WrapperTest { @Test public void test7 () { Object o1 = true ? new Integer (1 ) : new Double (2.0 ); System.out.println(o1); Object o2; if (true ) { o2 = new Integer (1 ); }else { o2 = new Double (2.0 ); } System.out.println(o2); } }
练习题2 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动态伸缩。
创建Vector对象:Vector v=new Vector(); 给向量添加元素:v.addElement(Object obj); // obj必须是对象 取出向量中的元素:Object obj = v.elementAt(0)、 注意第一个元素的下标是0,返回值是Object类型的。 计算向量的长度:v.size(); 若与最高分相差10分内:A等;20分内:B等;30分内:C等;其它:D等 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package com.base12._wrapper.exer1;import java.util.Scanner;import java.util.Vector;public class ScoreTest { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); Vector v = new Vector (); int maxScore = 0 ; for (; ; ) { System.out.print("请输入学生成绩(以负数代表输入结束):" ); int score = scanner.nextInt(); if (score < 0 ) break ; if (score > 100 ) { System.out.println("输入的成绩有误,请重新输入:" ); continue ; } v.addElement(score); if (maxScore < score) maxScore = score; } char level; for (int i = 0 ; i < v.size(); i++) { Object obj = v.elementAt(i); int score1 = (Integer) obj; if (maxScore - score1 < 10 ) { level = 'A' ; } else if (maxScore - score1 < 20 ) { level = 'B' ; } else if (maxScore - score1 < 30 ) { level = 'C' ; } else { level = 'D' ; } System.out.println("student - " + i + " score is " + score1 + ", level is " + level); } scanner.close(); } }