Integer类----装箱
1.Integer类的用途
Integer 一个整型数据用来存储整数,整数包括正整数,负整数和零。将整型数据存储起来,变成Integer对象。这个过程叫装箱,而将Integer对象变成整型数据,这个过程叫做拆箱。
Int是java的原始数据类型,Integer是java为int提供的封装类。且Integer类有两个父类,一个是object 还有一个是 Number抽象类。
2.如何将数据封装成Integer对象
2.1 装箱
方法1:通过new的方式,将数据封装成Integer对象。其中需要封装的数据可以是整型,还可以是纯数字的字符串
方法2:通过Integer.Valueof()方法
示例1:
public class integer { public static void main(String[] args) { Integer i1 = new Integer(2); Integer i2 = new Integer("123"); System.out.println(i1+" "+i2); }}
示例2:
public abstract class integer { public static void main(String[] args) { Integer i = Integer.valueOf(12); System.out.println(i); }}
2.2装箱过程(原理)
2.2.1 当需要封装的数据是整型时:
调用Integer类中构造方法将数据传入,并将数据赋值给Integer类中的value成员属性;
private final int value-属性value是用private和final关键字修饰了的,因此value属性不允许在类外访问且一旦在构造函数中赋予了初值就不会在改变,因为有final关键字,value是常量。
2.2.2 当需要封装的数据是纯数字字符串时:
调用参数是字符串的构造方法 ,将纯数字传入,通过Integer本类中的parseInt()方法将纯数字的字符串转化为整型数字。并将
parseint源码转化过程:
//将字符串和radix(表示进制默认的为十进制)传入 public static int parseInt(String s, int radix) throws NumberFormatException { //判断字符串是否为空值 if (s == null) { throw new NumberFormatException("null"); } //判断radix是否为小于二进制。Character.MIN_RADIX来自Character类中的常量 //public static final int MIN_RADIX = 2; if (radix Character.MAX_RADIX) { throw new NumberFormatException("radix " + radix + " greater than Character.MAX_RADIX"); } /*设置了几个局部变量 result表示结果 negative = false相当于开关(flag) len = s.length()字符串的长度 limit = -Integer.MAX_VALUE 设置限度 */ int result = 0; boolean negative = false; int i = 0, len = s.length(); int limit = -Integer.MAX_VALUE; int multmin; int digit; //查看字符串的长度是否大于0,如果大于0,则取第一个字符。 if (len > 0) { char firstChar = s.charAt(0); /*用取出来的字符与0的Ascii码值48比较, 如果小于48则说明该字符串不是纯数字可能为负数有(“-”)的字符串并往回抛出NumberFormatException(数字格式化异常) */ if (firstChar < '0') { // Possible leading "+" or "-" if (firstChar == '-') { negative = true; limit = Integer.MIN_VALUE; } else if (firstChar != '+') throw NumberFormatException.forInputString(s); if (len == 1) // Cannot have lone "+" or "-" throw NumberFormatException.forInputString(s); i++; }multmin = limit / radix;//为下面判断溢出做铺垫 //如果上面判断为flas则进入循环,继续往下判断 while (i < len) { // Accumulating negatively avoids surprises near MAX_VALUE /* digit = Character.digit(s.charAt(i++),radix); charAt()是String类中的方法而String继承了CharSequence接口,并实现了charAt()方法。该方法将用于判断i的值是否小于0或大于字符的长度,如果判断为flas则抛出 StringIndexOutOfBoundsException字符索引超出的异常,如果为true则返回 下标为i的字符。Character.digit(字符,radix); 调用character类中的实现CharacterData中的digit抽象方法时将字符强转为整型, 在调用抽象类CharacterData.of().digit()优化得到一个整数。 */ digit = Character.digit(s.charAt(i++),radix); //将的到的整数digit与0作比较,结果如果为flas,则抛出数字格式化错误 if (digit =0,那么则开始测试是否溢出,if (result < multmin) { throw NumberFormatException.forInputString(s); } //将result转化为十进制 result *= radix; if (result < limit + digit) { throw NumberFormatException.forInputString(s); } result -= digit; } } else { throw NumberFormatException.forInputString(s); } //如果negative为true返回 (负数)result否则 (正数)-result return negative ? result : -result; }
2.3自动装箱
不需要是通过new的方式,将数据封装为Integer类型。
示例:
public class integer { public static void main(String[] args) { Integer i2 = 123; Integer i1 = Integer.valueOf(123);System.out.println(i1==i2); }}
结果:
自动装箱成功,但是打印i1==i2,结果为true说明,i1和i2是同一个对象。只有这种说法才能让i1=i2的结果为true.这里就跟自动装箱的低层实现有关了
2.3.1 自动装箱的底层实现
自动装箱的底层是通过Integer.valueof()实现的。
具体过程:
public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
通过调用Integer类的内部类IntegerCache这个类中的valueof()方法,将数据与常量low和height比较。但是在IntegerCache这个类中有1个静态代码块,因此在代码块在加载时优先级加载
而这个静态代码块中有一个缓存区,将-128到127之间的数字封装成Integer对象;
静态代码块:
首先初始定义的一个局部变量 h = 127,然后定义了一个String类型的变量 ,并调用了系统中虚拟机的方法获取系统中的height的默认值值,将其赋值String变量。 String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
如果获取到的值为空则直接将h的值赋值给height.
如果获取的值不为空,则将该值转化为int类型并赋值给i变量,int i=parseInt(integerCacheHighPropValue);再将i的值与127比较取最大的一个的值并赋值给i;i = Math.max(i, 127);
再将i的值与Integer.MAX_VALUE-(low)-1比较,取其中的最小的一个值,目的时为了防止溢出,因为如果取的默认值超过了Integer.MAX_VALUE-(low)-1的值就会发生溢出。但是一般是不会发生,除非修改了虚拟机系统方法的默认值。
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
最后将h的值赋给height,height = h 范围(-128--127)
cache = new Integer[(high - low) + 1]; cache是一个数组,而这个数组是一个Integer类型的数组,其长度为[(height-low)+1];(256)
int j = low;将low赋值给j,因为low是一个常量,方便下面的操作。
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);通过循环将0-255的Integer对象放在cache[]数组中,相当于起了一个缓存作用。
assert IntegerCache.higth>= 127;assert 后跟boolean表达式,如果表达式为True则继续执行
否则抛出异常。在这里不改变系统默认值的情况下,则将继续执行。
因此只要输入的值的范围在【-128到127】之间就不会通过new来创建Integer对象,而是通过
IntegerCache 内部类中的cache[ ]数组中的封装的-128到127个Integer对象来赋值给Integer对象
的引用。