<small id="7ktuj"></small>
      <bdo id="7ktuj"></bdo>
        <mark id="7ktuj"></mark>

        <source id="7ktuj"></source>
        <small id="7ktuj"></small>

        ITPub博客

        首頁 > 應用開發 > Java > Java基本數據類型及其包裝類

        Java基本數據類型及其包裝類

        原創 Java 作者:蝴蝶飛啊飛 時間:2019-10-31 13:48:01 0 刪除 編輯

        一、基本數據類型的系統描述:

        1. 總述: Java 基本數據類型分為兩大類: boolean 類型和數值類型。數值類型可分為整數類型和浮點類型,而其中字符類型可單獨對待。所以 Java 只包含 8 種基本數據類型。

        !注意!字符串不是基本數據類型,字符串是一個類,是一個引用類型。這個在下一篇我們會仔細討論它!

        boolean 數值只有 true false ,不能用 0 代替。其他數值類型不能轉換成 boolean 。包裝類– Boolean

        byte 內存 8 位,無符號位時最大存儲 255 ,表數范圍: -128~127 。包裝類– Byte

        short 內存 16 位,無符號位時最大存儲 65536 ,表數范圍: -32768~32767 。包裝類– Short

        int 內存 32 位,無符號位時最大存儲 2 32 次方減 1 ,表數范圍:負的 2 31 次方到正的 2 31 次方減 1 。包裝類– Integer

        long 內存 64 位,無符號位時最大存儲 2 64 次方減 1 ,表數范圍:負的 2 63 次方到正的 2 63 次方減 1 。包裝類– Long

        float 內存 32 位,數據范圍在 3.4e-45~1.4e38 ,直接賦值時必須在數字后加上 f F 。包裝類– Float

        double 內存 64 位,數據范圍在 4.9e-324~1.8e308 ,賦值時可以加 d D 也可以不加。包裝類– Double

        char 16 位,存儲 Unicode 字符集,用單引號賦值。可以參與加減乘除運算的,也可以比較大小的!!包裝類– Character

        二、數據類型的包裝類理解(含部分源碼解析)

        首先要知道為什么Java 會為每一個基礎數據類型都提供一個相應包裝類的目的,在于將 Java 的所有東西都抽象成對象,可以更方便的控制和使用。這就是面向對象!

        然后對于包裝類,主要作用是:1. 作為和基本數據類型對應的類類型存在,方便涉及到對象的操作。 2. 包含每種基本數據類型的相關屬性如最大值、最小值等,以及相關的操作方法。

        下面我們將一起討論下包裝類中的重要源碼!!

        1. 深入 boolean 基本類型、 Boolean 類以及細節點:

        // 看接口是可序列化,是一個 final 修飾的類

        public final class Boolean implements java.io.Serializable,

                                              Comparable<Boolean>{

             // 看這兩個對應的原始對象。享元模式的使用,達到多個對象都使用一份內存。至于什么是享元,以及它與單例的區別,這里就不多說了。

         public static final Boolean TRUE = new Boolean(true);

         public static final Boolean FALSE = new Boolean(false);

         private final boolean value;

         // 兩個構造器,可見它是可以為 null 的啦,使用 Boolean 這個類的話

         public Boolean(boolean value) {

                this.value = value;

            }

             public Boolean(String s) {

                this(parseBoolean(s));

            }

             public static boolean parseBoolean(String s) {

                return ((s != null) && s.equalsIgnoreCase("true"));

            }

            //jdk 文檔建議用 valueOf 代替 new 方式來創建 Boolean 類對象。 new 創建的 Boolean 對象是不斷的新創建一個實例對象,而 valueOf 則是返回 Boolean 類里的靜態成員變量 , 也就是使用享元模式的那個對象。

            public static Boolean valueOf(String s) {

                return parseBoolean(s) ? TRUE : FALSE;

            }

            // 下面是令人困惑的設計了,我也是看了下 stackoverflow 里面討論才有點懂。

            // 原汁原味鏈接: http://stackoverflow.com/questions/3912303/boolean-hashcode

            //1. 使用質素是因為假如要把 Boolean 指插入到 hashtable 中,如果不是質素的話可能會比較容易造成哈希沖突。符合對象計算 hashcode 的時候通常會把各個屬性的 hashcode 相加然后再做 hash, 如果是比較小的質素,容易造成 hash 分布不均勻。

            //2. Maps 是可以包裹 Boolean 的,而如果 map 除了包含 Boolean 對象,還包含其他對象,那么如果不適當處理,就很容易有沖突了

         public static int hashCode(boolean value) {

                return value ? 1231 : 1237;

            }

            // 好恐怖和縝密的源碼設計。

        }

        總括下:

        1.boolean 是基礎數據類型,而 Boolean 是一個類。

        2.boolean 一般存在于桟空間中,而 Boolean 對象存在堆空間中。

        3.boolean true false 倆種值, Boolean 除了 true false 外,還有 null

        下面我們看份代碼:(解析在代碼中)

        public class Main {

            public static void main (String []args)

            {

                Boolean bool1 = Boolean.valueOf(true);       // 這里均使用 valueof 創建對象, new 創建的 Boolean 對象是不斷的新創建一個實例對象,而 valueOf 則是返回 Boolean 類里的靜態成員變量

                Boolean bool2 = Boolean.valueOf("True");    // 這里上一句代碼驗證使用 String 變量作為參數時,不區分大小寫的。

                Boolean bool3 = Boolean.valueOf("ASD");

                boolean x1 = bool1.booleanValue();

                boolean x2 = bool2.booleanValue();

                System.out.println("bool1:" + x1 + ",bool2:" + x2 + ",bool3:" + bool3);

                boolean x3 = bool1.equals(bool2);       // 這個就是驗證享元模式,使用的是同一個對象

                boolean x4 = bool1.equals(bool3);       // 肯定不是同一對象啦。

                System.out.println("bool1.equals(bool2):" + x3 + ",bool1.equals(bool3):" + x4);

                String str1 = Boolean.toString(bool1);      // 可見 Boolean 對象是可以轉換成字符的

                String str2 = Boolean.toString(false);      

                String str3 = bool3.toString();

                System.out.println("bool1:" + str1 + ",str2:" + str2 + ",bool3:" + str3);

                boolean x5 = Boolean.parseBoolean("ASD");         // 源碼是直接判斷然后與 true 對比,因此打印為 false

                System.out.println(x5);

            }

        }

        2. 深入 byte 基本類型

        先來份Byte 源碼

        // 也可以看到是一個 final 修飾的類,只能用,不能被繼承咯

        public final class Byte extends Number implements Comparable<Byte>{

        public static final int SIZE = 8;   // 只能是一個字節咯

        // 兩個構造器

        public Byte(byte value) {

                this.value = value;   // 傳入的要為 Byte 類型的值

            }

            public Byte(String s) throws NumberFormatException {

                this.value = parseByte(s, 10);  // 傳入的要求是可轉換成 Byte 的字符串

            }

            // 這個 Byte 做了緩存

            private static class ByteCache {

                private ByteCache(){}

                static final Byte cache[] = new Byte[-(-128) + 127 + 1];// 聲明緩存數組的長度為 256

                static {

                    for(int i = 0; i < cache.length; i++)

                        cache[i] = new Byte((byte)(i - 128));// 然后將 -128~127 進行緩存

                }

            }

            // 兩個解析字符串方法

            public static byte parseByte(String s, int radix)

                throws NumberFormatException {

                //radix 是外匯返傭http://www.kaifx.cn/解析字符串時候的基數,在此方法下有個解析基數的含義。

                int i = Integer.parseInt(s, radix);// 解析字符串并返回,所以 s 必須是 -128~127 的字符,至于為什么用這個方法 int 的包裝類方法來解析,一會我們會談到。

                if (i < MIN_VALUE || i > MAX_VALUE)

                    throw new NumberFormatException(

                        "Value out of range. Value:\"" + s + "\" Radix:" + radix);

                return (byte)i;

            }

            // 也是解碼轉碼方法,將 String 轉為 Byte

            public static Byte decode(String nm) throws NumberFormatException {

                int i = Integer.decode(nm);// 一會重點講解 Integer 的系列方法

                if (i < MIN_VALUE || i > MAX_VALUE)

                    throw new NumberFormatException(

                            "Value " + i + " out of range from input " + nm);

                return valueOf((byte)i);

            }

        }

        解釋radix 的作用

        b[0] = Byte.parseByte( 11 , 2) = 3

        表示 字符串11 2 為基數表示為 10 進制的 byte 值是 3 ,這里的 11 表示的是一個 2 進制數

        b[0] = Byte.parseByte( 11 , 3) = 4

        表示 字符串11 3 為基數表示為 10 進制的 byte 值是 4 ,這里的 11 表示的是一個 3 進制數

        // 另外這樣使用 byte 是不會報錯的:

        byte=55;

        // 因為會自動把 56 當成 byte 類型去處理的了。

        3. 就是重點的 int Integer

        先吃份源碼Integer 解析套餐

        public final class Integer extends Number implements Comparable<Integer> {

         public static final Class<Integer>  TYPE = (Class<Integer>) Class.getPrimitiveClass("int");// 原始類型 int Class 實例。

         // 所有可能的將數字表示為字符串的字符集合做緩存。

         final static char[] digits = {

                '0' , '1' , '2' , '3' , '4' , '5' ,

                '6' , '7' , '8' , '9' , 'a' , 'b' ,

                'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,

                'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,

                'o' , 'p' , 'q' , 'r' , 's' , 't' ,

                'u' , 'v' , 'w' , 'x' , 'y' , 'z'

            };

        // 兩個構造器

         public Integer(int value) {

                this.value = value;

            }

            public Integer(String s) throws NumberFormatException {

                this.value = parseInt(s, 10);// 涉及了 String 轉換成 int ,一會仔細討論這個。

            }

            // 像上面 Byte 類型中解釋的那樣的方法,返回第二個參數所指定的進制數的第一個參數的字符串表示形式。處理各種進制的 Integer.

            public static String toString(int i, int radix) {

                if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)             

                radix = 10;// 默認為 10 進制

                /* Use the faster version */         

                if (radix == 10) {             

                    return toString(i);         

                }

                char buf[] = new char[33];         

                boolean negative = (i < 0);         

                int charPos = 32;

                // 統一轉為負數去處理

                if (!negative) {             

                    i = -i;         

                }

                while (i <= -radix) {             

                    buf[charPos--] = digits[-(i % radix)];             

                    i = i / radix;         

                }         

                buf[charPos] = digits[-i];

                if (negative) {             

                    buf[--charPos] = '-';         

                }

                return new String(buf, charPos, (33 - charPos));     

            }

            // 一會有事例代碼演示這個,這個其實就是把 int 型包裝成 Integer 然后再轉化成 String 字符串

             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);

            }

            // toString 組合形成一方法去轉換成字符串咯

            static void getChars(int i, int index, char[] buf) {

                int q, r;

                int charPos = index;

                char sign = 0;

                if (i < 0) { // 如果 i 為負數,則設置 i 的符號字符為 '-'

                    sign = '-';  // 確定正負數

                    i = -i;  // 將負數轉化為正數處理,提高效率

                }

                // Generate two digits per iteration

                while (i >= 65536) { // 如果 i 大于 65536 ,則每一次都獲取十位和個位上的數字對應的字符。將值判斷大小后取每個數字,較大的數字一次取兩位(大數字運算消耗大)

                    q = i / 100;

                // really: r = i - (q * 100);

                    r = i - ((q << 6) + (q << 5) + (q << 2)); // 利用位運算,每次獲得 i 的最后兩位數,不斷循環提取處理

                    i = q;// 重新賦值,準備下一次循環

                    buf [--charPos] = DigitOnes[r]; // 存儲 r 中在個位數集合中對應的字符

                    buf [--charPos] = DigitTens[r]; // 存儲 r 中在十位數集合中對應的字符

                }

                // Fall thru to fast mode for smaller numbers

                // assert(i <= 65536, i);

                for (;;) { //i<65536 的情況,小數字運算消耗較小,故一次只取一位

                    q = (i * 52429) >>> (16+3);//52429/(2*19) 約等于 1 ,此處這樣設計是為了提高精度

                    r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ... // 每次獲得 i 的最后兩位數

                    buf [--charPos] = digits [r];// 取最后一位的數字  

                    i = q;// 重新賦值,準備下一次循環  

                    if (i == 0) break;

                }

                if (sign != 0) {

                    buf [--charPos] = sign; // 設置符號

                }

            }

            // 下面兩個是用來確定字符串長度的。

            // 定義 sizeTable 表示 int 中每個位數中最大的數,用于簡便確定 int 數的長度。

            final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,

                                              99999999, 999999999, Integer.MAX_VALUE };

            // 使用上面的 sizeTable 定義來確定 int 數的字符串表示長度。           

            static int stringSize(int x) {

                for (int i=0; ; i++)

                    if (x <= sizeTable[i])

                        return i+1;

            }

            // 炒雞重要的方法啦!! parseInt(String s,int radix) 使用第二個參數指定的基數,將字符串參數解析為有符號的整數。 parseInt(String s) 只能將數字字符串轉化十進制數

             public static int parseInt(String s, int radix)

                        throws NumberFormatException

            {

                /*

                 * WARNING: This method may be invoked early during VM initialization

                 * before IntegerCache is initialized. Care must be taken to not use

                 * the valueOf method.

                 */

                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");

                }

                int result = 0;

                boolean negative = false;

                int i = 0, len = s.length();//i 表示當前遍歷的 s 的位數

                int limit = -Integer.MAX_VALUE;// 設置最小值為負的 Integer 的最大值

                int multmin;

                int digit;

                if (len > 0) {// 如果字符串長度大于 0 ,則進行轉換

                    char firstChar = s.charAt(0);// 獲取第一位字符

                    if (firstChar < '0') { // Possible leading "+" or "-"

                        if (firstChar == '-') {// 判斷是否為負數

                            negative = true;

                            limit = Integer.MIN_VALUE;// 將限制轉換為 Integer 的最小值,不能小于 Integer 的最小值  

                        } else if (firstChar != '+')

                            throw NumberFormatException.forInputString(s);// 第一個 char 不為 + 也不為 - ,則拋出異常  

                        if (len == 1) // Cannot have lone "+" or "-"

                            throw NumberFormatException.forInputString(s);// 若只有一個符號,則拋出異常

                        i++;

                    }

                    multmin = limit / radix;// 設定不同進制下的極限值  

                    while (i < len) {// 進行進制的轉換

                        // Accumulating negatively avoids surprises near MAX_VALUE

                        digit = Character.digit(s.charAt(i++),radix);// 將數字字符串轉換成要求的進制數,使用工具類,每次遍歷對一個字符進行操作轉換  

                        if (digit < 0) {

                            throw NumberFormatException.forInputString(s);

                        }

                        if (result < multmin) {

                            throw NumberFormatException.forInputString(s);

                        }

                        result *= radix;

                        if (result < limit + digit) {

                            throw NumberFormatException.forInputString(s);

                        }

                        result -= digit;

                    }

                } else {

                    throw NumberFormatException.forInputString(s);

                }

                return negative ? result : -result;// 根據符號返回正數還是負數

            }

            // 看吧,我們經常用的 parseInt 只是個幫我們制定好 10 進制規則的靜態方法

            public static int parseInt(String s) throws NumberFormatException {

                return parseInt(s,10);

            }

            // 強大的內部類緩存機制嗎,內部字符緩存類

        private static class IntegerCache {

        // 緩存的下界, -128 ,不可變  

                static final int low = -128;

                 // 緩存上界,暫為 null

                static final int high;

                static final Integer cache[];// 利用數組來緩存

                // 原理:初始化數組將一定范圍的整數放到 cache 數組中,然后在調 valueOf 方法的時候首先判斷范圍然后從緩存數組中去抓取數據

                static {

                    // high value may be configured by property

                    // 緩存上屆,可以通過 JVM 屬性來配置

                    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);

                            // Maximum array size is Integer.MAX_VALUE

                            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);

                        } catch( NumberFormatException nfe) {

                            // If the property cannot be parsed into an int, ignore it.

                        }

                    }

                    high = h;

        // 獲取 Integer 中所有能保存的數據,初始化緩存數組

                    cache = new Integer[(high - low) + 1];

                    int j = low;

                    // 緩存所有 Integer 的數據

                    for(int k = 0; k < cache.length; k++)

                        cache[k] = new Integer(j++);

                    // range [-128, 127] must be interned (JLS7 5.1.7)

                    assert IntegerCache.high >= 127;

                }

                private IntegerCache() {}

            }

            // 還有這個我們經常用的,官方也推薦使用這個方法去創建對象的

               public static Integer valueOf(int i) {

               // 如果 i Integer 緩存中,則直接取出

                if (i >= IntegerCache.low && i <= IntegerCache.high)

                    return IntegerCache.cache[i + (-IntegerCache.low)];

               // 否則,直接創建一個實例

                return new Integer(i);

            }

        }

        使用Integer 事例代碼:

        // 會打印出 10 這個字符串

            public static void main (String []args) {

                Integer i =null;

                i = Integer.valueOf(10);

                System.out.println(">>>>"+i.toString());

            }

        public static void main(String[] args) {

                Integer a1 = 1;

                Integer a2 = 1;

                Integer b1 = 200;

                Integer b2 = 200;

                Integer c1 = Integer.valueOf(1);

        //        Integer c2 = new Integer(1);       官方不推薦這種建對象的方法喔

                Integer c2 = Integer.valueOf(1);

                Integer d1 = Integer.valueOf(200);

                Integer d2 = Integer.valueOf(200);

                System.out.println("a1==a2?" + (a1 == a2));

                System.out.println("b1==b2?" + (b1 == b2));

                System.out.println("c1==c2?" + (c1 == c2));

                System.out.println("d1==d2?" + (d1 == d2));

            }

        上面一段代碼的運行結果就是我們要深思的東西啦,也是結合源碼要懂的東西。

        a1==a2? true

        b1==b2? false

        c1==c2? false

        d1==d2? false

        第一個為什么是true 呢,因為 Integer 的緩存機制嘛,剛剛我們看到的,緩存了 [-128,127] ,這些可以直接取出。而剩余的為什么是 false ,因為他們都超過了緩存的那個范圍,就建了個新對象咯。

        至于short float double 這類的包裝類設計原理有的跟 Integer 差不多,但是比如 Double ,很難去閱讀,感覺自己程度還不夠,以后會補上。而 Character 這個包裝類,,源碼 8000 多行,我們就討論它的一些基本知識吧。

        4.Character 的基本了解:

        Character 類在對象中包裝一個基本類型 char 的值。 Character 類型的對象包含類型為 char 的單個字段。該類提供了幾種方法,以確定字符的類別(小寫字母,數字,等等),并將字符從大寫轉換成小寫,從小寫轉換成大寫。 Character 類的方法和數據是通過 UnicodeData 文件中的信息定義的。至于 Unicode 大家就百度了解下就好。

        來自 “ ITPUB博客 ” ,鏈接:http://www.ep4tq.com/69946279/viewspace-2662071/,如需轉載,請注明出處,否則將追究法律責任。

        下一篇: Java基礎中的IO流
        請登錄后發表評論 登錄
        全部評論
        管他誰是誰非,做自己的主宰,我是這條街最亮的崽!

        注冊時間:2019-08-22

        • 博文量
          49
        • 訪問量
          21835
        妹子图每日分享