受欢迎的免费网站建设,seo兼职优化,广州注册公司价格,html5旅游网站源码当你掌握Java语言到了一定的阶段#xff0c;或者说已经对Java的常用类和API都使用的行云流水。你会不会有一些思考#xff1f;比如#xff0c;这个类是如何设计的#xff1f;这个方法是怎么实现的#xff1f;接下来的一系列文章#xff0c;我们一起学习下Java的一些常见类… 当你掌握Java语言到了一定的阶段或者说已经对Java的常用类和API都使用的行云流水。你会不会有一些思考比如这个类是如何设计的这个方法是怎么实现的接下来的一系列文章我们一起学习下Java的一些常见类的源码。本篇一起分析下Integer的源码。
目录
一、两道Integer的题目
二、Integer类图
三、String转int
1、Integer.parseInt
2、Integer.valueOf
四、总结 一、两道Integer的题目 可能有些同学java水平比较高或者认为自己没必要去看Integer源码。那你不妨看下接下来这几道题目看看你是否都能答对。
1、如下代码输出什么
public class IntegerTest1 {public static void main(String[] args) {Integer i1 100;Integer i2 100;Integer i3 200;Integer i4 200;System.out.println(i1 i2);System.out.println(i3 i4);}
}
答案是true false 2、如下代码输出什么
public class IntegerTest {public static void main(String[] args) {String s 10;System.out.println(Integer.getInteger(s));}
}
答案是null咦为什么不是10 如果这两道题目都答对了那你可以叉掉这篇文章因为我也不想浪费你的时间。如果你答错了那么不妨一起学习下Integer的源码
二、Integer类图 那么接下来我们一起看下Integer的源码吧。Integer源码不算短1800行代码。其中有很多api是不常用的因此我们也仅去挑一些常用的api去看下其实现。如下是Integer及其关联类/接口的类图 通过Integer类的类图我们总结下它的特点 Integer类继承自抽象类NumberInteger类实现了Comparable接口Integer类使用final修饰因此不可以有子类不能被继承 三、String转int 在日常工作中我们经常会将一个代表数字的String转为int那么Java给我们提供了两个方法
1、Integer.parseInt public static int parseInt(String s) throws NumberFormatException {return parseInt(s,10);} 在使用这个方法的时候我们需要注意trycatch一下NumberFormatException否则当输入的String不是数字或者超过integer的范围时会产生异常。 另外该方法默认是10进制当然我们也可以调用两个参数的方法传入进制去转为其他进制的int但这不常用
public static int parseInt(String s, int radix)throws NumberFormatException{...} 接下来详细看下该方法的实现 首先会判断传入的String不为null检验传入的进制参数在范围内[2 , 36]而且会判断字符串的长度大于0否则会抛出NumberFormatException if (s null) {throw new NumberFormatException(null);}if (radix Character.MIN_RADIX) {throw new NumberFormatException(radix radix less than Character.MIN_RADIX);}if (radix Character.MAX_RADIX) {throw new NumberFormatException(radix radix greater than Character.MAX_RADIX);}if (len 0) {...} else {throw NumberFormatException.forInputString(s);} 当字符串满足转化为int的条件时就执行将String转为int的代码上述被...省略的代码。我们也分两步来看 首先根据字符串的首字符判断是正数、负数或是非法。 char firstChar s.charAt(0);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;} 1如果第一个字符是-会把表示正负数的negative置为true同时把其limit置为Integer的最小值 2如果不是-且如果不是那说明是其他的字符抛出异常 3如果首字符是或-但是长度为1说明是或-也是非数字抛出异常。 4如果首字符合法那么i接下来看非符号的字符。 当然如果首字符不是符号而是数字那么就直接走接下来的代码 int multmin limit / radix;int result 0;while (i len) {// Accumulating negatively avoids surprises near MAX_VALUEint digit Character.digit(s.charAt(i), radix);if (digit 0 || result multmin) {throw NumberFormatException.forInputString(s);}result * radix;if (result limit digit) {throw NumberFormatException.forInputString(s);}result - digit;}return negative ? result : -result; 1遍历字符串的字符调用digit函数该函数在不能转为数字时返回-1 2如果有字符不是数字digit0,那么抛出异常。 3如果没问题那就一步步计算转为int会判断是否超过范围超过范围则抛出异常 4最后如果是负数返回result如果是正数返回-result 在这里可能有的同学没看懂为什么负数返回的是result而正数返回的是-result。我们把字符串数字转为十进制的方法比如把1234转为十进制其实是这么来的
1 ✖️10 2✖️10 3✖️10 4 12 ✖️10 3 ✖️10 4 120 3✖️10 4 123✖️10 4 1230 4 1234 而方法里面其实是反过来实现的
-1 ✖️10- 2✖️10 - 3✖️10 - 4 -12 ✖️10 - 3 ✖️10 - 4 -120 - 3✖️10 - 4 -123✖️10 - 4 -1230 - 4 -1234 所以它用的不是正向累加法而是负向累加法。其实代码里面也有注释负向累加避免在最大值附近发生意外
// Accumulating negatively avoids surprises near MAX_VALUE
2、Integer.valueOf 第二种方法就是Integer.valueOf该方法最后还是调用的parseInt。注意其返回值是Integer而不是int。不过现在已经不用unboxing了可以直接使用int去接收返回值。 public static Integer valueOf(String s, int radix) throws NumberFormatException {return Integer.valueOf(parseInt(s,radix));} 接下来看看valueOf的实现 public static Integer valueOf(int i) {if (i IntegerCache.low i IntegerCache.high)return IntegerCache.cache[i (-IntegerCache.low)];return new Integer(i);} suprise来了Integer.valueOf( int i)这个方法出现了IntegerCache这个内部类而且会返回cache里的对象或者一个新的Integer对象。那么IntegerCache是什么 private static class IntegerCache {static final int low -128;static final int high;static final Integer[] cache;static Integer[] archivedCache;private IntegerCache() {}static {int h 127;String integerCacheHighPropValue VM.getSavedProperty(java.lang.Integer.IntegerCache.high);int size;if (integerCacheHighPropValue ! null) {try {size Integer.parseInt(integerCacheHighPropValue);size Math.max(size, 127);h Math.min(size, 2147483518);} catch (NumberFormatException var6) {}}high h;VM.initializeFromArchive(Integer.IntegerCache.class);size high - -128 1;if (archivedCache null || size archivedCache.length) {Integer[] c new Integer[size];int j -128;for(int k 0; k c.length; k) {c[k] new Integer(j);}archivedCache c;}cache archivedCache;assert high 127;}} 可以看出Integer内部维护了一个IntegerCache范围是[-128,127]。valueOf方法如果数值在[-128,127]之间便返回指向IntegerCache.cache中已经存在的对象的引用否则创建一个新的Integer对象。 这其实解答了我们的第一个问题。 在这里顺便也看下我们的第二个问题为什么Integer.getInteger10返回的是null而不是10。其实调用的是System.getProperty跟String转int半毛钱关系没有 public static Integer getInteger(String nm, Integer val) {String v null;try {v System.getProperty(nm);} catch (IllegalArgumentException | NullPointerException e) {}if (v ! null) {try {return Integer.decode(v);} catch (NumberFormatException e) {}}return val;}
四、总结 其实Integer我们常用的无非就是这两个String转int的方法Integer还提供了一些简单的计算方法例如maxminsum其实我们也用不到。还有intValue方法从java1.6开始我们也不需要拆箱unboxing了所以也用不到。 本篇基于Integer的两个常用方法看了其关键代码的实现也知道了其内部维护着一个缓存。通过分析其源码实现也解答了开篇抛出的两个问题。