zoukankan      html  css  js  c++  java
  • java Integer与int详解 01

    心得:
    一周前和一位刚入职阿里蚂蚁金融的学长进行了一次会谈:总的来说,java学了一个学期,可能是急于求成(我身上最大的缺陷),就直接学JAVA的JDBC编程(MYSQL在大二上学期就开始在用了:2002 1064 HY2000 1042 2053等的错踩到心碎,不过踩坑不怕,重要的是你对MYSQL认识了多少,现在一般也是偷懒,很少写.sql建表啊等等操作,哈哈哈都是视图工具Navcat for mysql:需要的同学可以了解一下)
    我清晰的记得我在学java第二天学的多线程,做了一个买面包的多线程小demo,说实话,现在已经忘的一干二净,可能唯一记住的就是sleep()函数了...个人心得:不管学什么,都得循序渐进
    学长在“会谈”一直在强调基础,那么java基础是什么呢?一门语言的基础永远不会是老师讲的那些:类的访问权限、包的访问权限,static是一个类静态变量、怎么使用import啊等等肤浅到学了和没学一样的东西(可能是王某愚见....),学长考了我一道题:

       Integer a=200;
       Integer b=200;
       Integer a1=2;
       Integer b1=2;
       System.out.println(a==b); //false   1
       System.out.println(a1==b1); //true  2


    我再加一个:   

    1   Integer c=new Integer(200);
    2   Integer d=new Integer(200);
    3   System.out.println(c==d); //false    3


    很简单:我很快就说出了正确答案,但学长的问题来了:
      1.Integer对象和int数据类型的区别是什么?
      2.既然知道缓存,那么缓存到了哪里?为什么缓存?Integer、int的适用场景分别是什么?
      3.System.out.println(a.equals(b)); //true 为什么? integer既然继承自Object,那么你能说一下Object都有什么方法吗?
      4.不同类型的equals()方法是相同的吗?

      5.既然知道自动装箱和自动拆箱,那么具体什么时候发生这种隐式转化?

    首先是:

    public final class Integer extends Number implements Comparable<Integer> {}
       //Integer 的类声明,第一句要注意三个点:Number类了解多少?Comparable<T>泛型比较接口了解多少?CompareTo()函数的实现原则?


      问题一:
       Integer 是int的包装类,在Integer对象里边包含了一个int基本类型的私有属性值

    1     /**
    2      * The value of the {@code Integer}.
    3      *
    4      * @serial
    5      */
    6     private final int value;
    View Code

      并且Integer也提供了很多供我们使用的方法:
       我们从构造函数说起:
       1>.向构造函数传int值
      

    public Integer(int value) {
            this.value = value; //为value赋值
        }


       也就是说,Integer c=new Integer(200);  这一行相当于是Integer对象里面的私有属性value的赋值

      2> Integer i=2;

      经过断点测试: 这一句代码会调用Integer的一个函数:ValueOf() 涉及到缓存(IntegerCache),在第二个问题里边会详细解释

    1     public static Integer valueOf(int i) {
    2         if (i >= IntegerCache.low && i <= IntegerCache.high)
    3             return IntegerCache.cache[i + (-IntegerCache.low)];
    4         return new Integer(i);
    5     }

    还有很多ValueOf()的重载函数:基本上都是parseInt()函数的调用

    1    public static Integer valueOf(String s, int radix) throws   NumberFormatException {
    2         return Integer.valueOf(parseInt(s,radix));
    3     }
    4     public static Integer valueOf(String s) throws NumberFormatException {
    5         return Integer.valueOf(parseInt(s, 10));
    6     }


      3> 向构造函数传String字符串

     1 public Integer(String s) throws NumberFormatException {
     2         this.value = parseInt(s, 10); //10为进制
     3     }
     4     public static int parseInt(String s, int radix)
     5                 throws NumberFormatException   //数字格式异常
     6     {
     7 
     8         if (s == null) {
     9             throw new NumberFormatException("null");
    10         }
    11 
    12         if (radix < Character.MIN_RADIX) { //java.lang.Character了解多少
    13             throw new NumberFormatException("radix " + radix +
    14                                             " less than Character.MIN_RADIX");
    15         }
    16 
    17         if (radix > Character.MAX_RADIX) {
    18             throw new NumberFormatException("radix " + radix +
    19                                             " greater than Character.MAX_RADIX");
    20         }
    21 
    22         int result = 0;
    23         boolean negative = false;
    24         int i = 0, len = s.length();
    25         int limit = -Integer.MAX_VALUE;   //@Native public static final int MAX_VALUE = 0x7fffffff; @Native 了解多少?
    26         int multmin;
    27         int digit;
    28 
    29         if (len > 0) { //不为空
    30             char firstChar = s.charAt(0); //String类的操作方法了解多少
    31             if (firstChar < '0') { // Possible leading "+" or "-"   '-'<'0'&&'+'<'0' true  ASCLL码的比较  ‘1’<'0' 数据类型的自动转化 (String)‘1’=》(int)1 
     32                 if (firstChar == '-') {
    33                     negative = true;  //是一个负数
    34                     limit = Integer.MIN_VALUE;
    35                 } else if (firstChar != '+')
    36                     throw NumberFormatException.forInputString(s);
    37 
    38                 if (len == 1) // Cannot have lone "+" or "-"
    39                     throw NumberFormatException.forInputString(s);
    40                 i++; 
    41             }
    42             multmin = limit / radix; 
    43             while (i < len) {
    44                 // Accumulating negatively avoids surprises near MAX_VALUE
    45                 digit = Character.digit(s.charAt(i++),radix);  //java.lang.Character.digit()方法用法 : 在指定的基数(radix)返回字符ch的数值 //Character.digit('0',10)=0; Character.digit('a',10);=-1
    46                 if (digit < 0) {
    47                     throw NumberFormatException.forInputString(s);
    48                 }
    49                 if (result < multmin) {
    50                     throw NumberFormatException.forInputString(s);
    51                 }
    52                 result *= radix; //数值进位制的变化
    53                 if (result < limit + digit) {  //结果如果小于所能表示的最小值
    54                     throw NumberFormatException.forInputString(s);
    55                 }
    56                 result -= digit;
    57             }
    58         } else {
    59             throw NumberFormatException.forInputString(s);
    60         }
    61         return negative ? result : -result;
    62     }

     4>Integer的ToString()实现(移位运算没看懂......)

     final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
    99999999, 999999999, Integer.MAX_VALUE };


    public static String toString(int i) { if (i == Integer.MIN_VALUE) return "-2147483648"; int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); char[] buf = new char[size]; getChars(i, size, buf); return new String(buf, true); }
    static int stringSize(int x) { for (int i=0; ; i++) if (x <= sizeTable[i]) //本人觉得这里是一个非常巧妙的设计 return i+1; } static void getChars(int i, int index, char[] buf) { int q, r; int charPos = index; char sign = 0; if (i < 0) { sign = '-'; i = -i; } // Generate two digits per iteration while (i >= 65536) { q = i / 100; // really: r = i - (q * 100); r = i - ((q << 6) + (q << 5) + (q << 2)); i = q; buf [--charPos] = DigitOnes[r]; buf [--charPos] = DigitTens[r]; } // Fall thru to fast mode for smaller numbers // assert(i <= 65536, i); for (;;) { q = (i * 52429) >>> (16+3); //????这个为什么是52429我也不知道......但是如果你打几个断点...看看结果还是能看懂的....hhh r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... buf [--charPos] = digits [r]; i = q; if (i == 0) break; } if (sign != 0) { buf [--charPos] = sign; } }

     当然还有很多函数,比如:

    public static Integer getInteger(String nm, Integer val):返回具有指定名称的系统属性的整数值:注意是返回一个系统属性的属性值,

    问题又来了:System 系统类了解多少???(走到哪里都会引发一堆一堆的问题.....最后一定要总结),我就给大家粘贴一下代码吧:

     1  public static Integer getInteger(String nm, int val) {
     2         Integer result = getInteger(nm, null);
     3         return (result == null) ? Integer.valueOf(val) : result;
     4     }
     5 
     6     public static Integer getInteger(String nm, int val) {
     7         Integer result = getInteger(nm, null);
     8         return (result == null) ? Integer.valueOf(val) : result;
     9     }
    10 
    11 
    12 
    13 public static Integer getInteger(String nm, Integer val) {
    14         String v = null;
    15         try {
    16             v = System.getProperty(nm);
    17         } catch (IllegalArgumentException | NullPointerException e) {
    18         }
    19         if (v != null) {
    20             try {
    21                 return Integer.decode(v);
    22             } catch (NumberFormatException e) {
    23             }
    24         }
    25         return val;
    26     }
    27  public static Integer decode(String nm) throws NumberFormatException {
    28         int radix = 10;
    29         int index = 0;
    30         boolean negative = false;
    31         Integer result;
    32 
    33         if (nm.length() == 0)
    34             throw new NumberFormatException("Zero length string");
    35         char firstChar = nm.charAt(0);
    36         // Handle sign, if present
    37         if (firstChar == '-') {
    38             negative = true;
    39             index++;
    40         } else if (firstChar == '+')
    41             index++;
    42 
    43         // Handle radix specifier, if present
    44         if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
    45             index += 2;
    46             radix = 16;
    47         }
    48         else if (nm.startsWith("#", index)) {
    49             index ++;
    50             radix = 16;
    51         }
    52         else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
    53             index ++;
    54             radix = 8;
    55         }
    56 
    57         if (nm.startsWith("-", index) || nm.startsWith("+", index))
    58             throw new NumberFormatException("Sign character in wrong position");
    59 
    60         try {
    61             result = Integer.valueOf(nm.substring(index), radix);
    62             result = negative ? Integer.valueOf(-result.intValue()) : result;
    63         } catch (NumberFormatException e) {
    64             // If number is Integer.MIN_VALUE, we'll end up here. The next line
    65             // handles this case, and causes any genuine format error to be
    66             // rethrown.
    67             String constant = negative ? ("-" + nm.substring(index))
    68                                        : nm.substring(index);
    69             result = Integer.valueOf(constant, radix);
    70         }
    71         return result;
    72     }
    View Code

     第二个问题:缓存(IntegerCache)先上代码:

     1  private static class IntegerCache {
     2         static final int low = -128;
     3         static final int high;
     4         static final Integer cache[];
     5 
     6         static {
     7             // high value may be configured by property  high的值可能取决于不同的操作系统,
    //据查阅:在jav5之前,缓存范围是写死在-128-127之间的,但是在 Java 6 中,
    //最大值映射到 java.lang.Integer.IntegerCache.high,可以使用 JVM 的启动参数设置最大值。
    //这使我们可以根据应用程序的实际情况灵活地调整来提高性能,
    8 int h = 127; 9 String integerCacheHighPropValue = 10 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    //之前一直认为Integer是缓存在JVM里边的,原来是自己没有充分认识到JVM、JDK、JRE的真正区别。
    //查阅资料后,Integer是缓存在JDK里的.....虽然现在也不是很理解
    String a = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");//???
    我尝试了一下,疑惑加一
    //String b = sun.misc.VM.getSavedProperty("high"); =》null
    //String c = System.getProperty("java.lang.Integer.IntegerCache.high"); =》null
    //String d = System.getProperty("high"); =》null?????
    11 if (integerCacheHighPropValue != null) { 12 try { 13 int i = parseInt(integerCacheHighPropValue); 14 i = Math.max(i, 127); 15 // Maximum array size is Integer.MAX_VALUE 16 h = Math.min(i, Integer.MAX_VALUE - (-low) -1); 17 } catch( NumberFormatException nfe) { 18 // If the property cannot be parsed into an int, ignore it. 19 } 20 } 21 high = h; 22 23 cache = new Integer[(high - low) + 1]; 24 int j = low; 25 for(int k = 0; k < cache.length; k++) 26 cache[k] = new Integer(j++); 27 28 // range [-128, 127] must be interned (JLS7 5.1.7) 29 assert IntegerCache.high >= 127; //断言了解多少? 30 } 31 32 private IntegerCache() {} 33 }

    了解了IntegerCache缓存类:再来看ValueOf函数()

    1     public static Integer valueOf(int i) {
    2         if (i >= IntegerCache.low && i <= IntegerCache.high)
    3             return IntegerCache.cache[i + (-IntegerCache.low)];
    4         return new Integer(i);
    5     }
    1 Integer a=12 
    3 Integer b=14 
    5 Integer c=200
    7 Integer d=200;

    调用valueOf函数之后,确定i是否在缓存范围内,如果在,返回已经缓存下来的,如果不在,就返回一个新的Integer对象

    故:a和b其实指向的是同一个Integer对象,c和d返回两个 堆地址不同的但是value相同的Integer对象。

    引用类型存在堆中,基本类型与引用存在栈中,这是再基本不过的操作...

    补充:

    这种缓存行为不仅适用于Integer对象。我们针对所有整数类型的类都有类似的缓存机制。
    有 ByteCache 用于缓存 Byte 对象
    有 ShortCache 用于缓存 Short 对象
    有 LongCache 用于缓存 Long 对象
    有 CharacterCache 用于缓存 Character 对象
    Byte,Short,Long 有固定范围: -128 到 127。对于 Character, 范围是 0 到 127。除了 Integer 可以通过参数改变范围外,其它的都不行


      第三个问题:equals()函数

    /**
         * Returns the value of this {@code Integer} as an
         * {@code int}.
         */
        public int intValue() {
            return value;
        }
    1  public boolean equals(Object obj) {
    2         if (obj instanceof Integer) {
    3             return value == ((Integer)obj).intValue();
    4         }
    5         return false;
    6     }
    7
    8 Integer a=200;
    9 Integer b=200;
    10 a.equals(b) //true 实际比较的是包装类中的value值,(int)200和(int)200必定会相等,这就解决了缓存带来的差异

    接下来我将贴几个equals():

    String类的

     1  public boolean equals(Object anObject) {
     2         if (this == anObject) {
     3             return true; //栈里指向堆的地址相同==引用指向通过一个对象
     4         }
     5         if (anObject instanceof String) {
     6             String anotherString = (String)anObject;
     7             int n = value.length;
     8             if (n == anotherString.value.length) {
     9                 char v1[] = value;
    10                 char v2[] = anotherString.value;
    11                 int i = 0;
    12                 while (n-- != 0) {
    13                     if (v1[i] != v2[i])
    14                         return false; //char数组的依次比较,String中的value又是什么呢?
    15                     i++;
    16                 }
    17                 return true;
    18             }
    19         }
    20         return false;
    21     }
    1 public final class String
    2     implements java.io.Serializable, Comparable<String>, CharSequence {
    3     /** The value is used for character storage. */
    4     private final char value[];
    5  ......
    6 }
    View Code

    Object 的equals()

    1  public boolean equals(Object obj) {
    2         return (this == obj);
    3     }

    Object作为所有对象的直接父类...大多数的对象都是要重写equals函数;

    第四个问题:Object的函数:
    这个我本来就知道toString()、hasCode()、equals()、clone();

    但是通过看了看源码:发现Thread类继承自Object,所以必然会有有关线程的函数...那么问题来了...run()、sleep()又是哪里来的????

    public final native void notify();
    
    public final native void notifyAll();
    
    public final native void wait(long timeout) throws InterruptedException;

    第五个问题:autoboxing、unboxing https://www.cnblogs.com/wang-yaz/p/8516151.html

    有一个前辈的博客写的很灵性:两句总结完毕

     Integer a = 99; //自动装箱 相当于调用了Integer的valueOf()函数
     int b = a;//自动拆箱 调用了intValue()函数

    Integer a1=10;
    int a2=10;
    System.out.println(a2==a1) //true 懂了原理,这题也太简单了:原理:包装类和基本类型进行运算时,隐式自动拆箱......

    之前写的:java基本数据类型的博客:
       https://www.cnblogs.com/laiso/p/8672524.html

    遗留的问题:

    1.移位运算

    2.@Native

    3.Character类

    4.Number类

    5.String 类

    6.断言

    7.System类

  • 相关阅读:
    C# 使用 sid 连接 Oracle(无需安装 Oracle 客户端)
    命令模式(Command Pattern)
    仅仅使用Google就完成了人生第一次破解
    GeoServer跨域问题
    List与DataTable相互转换
    GeoServer2.14.1修改端口
    坐标转换C#(Gcj02、wgs84、bd09互转)
    nginx启动报错(1113: No mapping for the Unicode character exists in the target multi-byte code page)
    C# 操作 Mongodb
    DocumentFormat.OpenXml导出word合并(文件被另一个进程占用)
  • 原文地址:https://www.cnblogs.com/laiso/p/9256120.html
Copyright © 2011-2022 走看看