java基本數據類型與包裝類間的轉換

基本數據類型之間的轉換規則

  1. 在一個雙操做數以及位運算等算術運算式中,會根據操做數的類型將低級的數據類型自動轉換爲高級的數據類型(向低轉有可能出現值範圍溢出的異常)分爲如下幾種狀況:
    (優先級 double > float > long > int > (byte = short = char) )
    1. 只要兩個操做數中有一個是double類型的,另外一個將會被轉換成double類型,而且結果也是double類型;
    2. 只要兩個操做數中有一個是float類型的,另外一個將會被轉換成float類型,而且結果也是float類型;
    3. 只要兩個操做數中有一個是long類型的,另外一個將會被轉換成long類型,而且結果也是long類型;
    4. 兩個操做數(包括byte、short、int、char)都將會被轉換成int類型,而且結果也是int類型。
  2.  若是低級類型爲char型,向高級類型(整型)轉換時,會轉換爲對應ASCII碼值,再作其它類型的自動轉換。
  3. 對於byte,short,char三種類型而言,他們是平級的,所以不能相互自動轉換,可使用下述的強制類型轉換。 eg:short i=99 ; char c=(char)i; System.out.println("output:"+c)
  4. 不能在布爾值和任何數字類型間強制類型轉換;
  5.  不一樣級別數據類型間的強制轉換,可能會致使溢出或精度的降低。
  6. 當字節類型變量參與運算,java做自動數據運算類型的提高,將其轉換爲int類型。eg:byte b;  b=3;  b=(byte)(b*3);//必須聲明byte

裝箱&拆箱

裝箱都是執行valueOf方法:若是有緩存將斷定是否在緩存範圍內,不然new。html

拆箱則是執行xxxValue方法!<floatValue、longValue、intValue。。。>java

eg.數組

public static boolean isSuspend(Double code) {
        return code == (int) 1;
    }

    public static void main(String[] args) {
        isSuspend(2d);
    }

入參先作裝箱處理Double.valueOf;再作拆箱處理Double.doubleValue。
說明:拆箱與當前本身的包裝類有關!緩存

Java 語言規範中的緩存行爲

在 Boxing Conversion 部分的Java語言規範(JLS)規定以下:oracle

詳情可見: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.7 下的 【5.1.7. Boxing Conversion】、【5.1.8. Unboxing Conversion】app

if the value p being boxed is an integer literal of type int between -128 and 127 inclusive (§3.10.1), or the boolean literal true or false (§3.10.3), or a character literal between '\u0000' and '\u007f' inclusive (§3.10.4), then let a and b be the results of any two boxing conversions of p. It is always the case that a == b.
若是一個變量 p 的值屬於:-128至127之間的整數,true 和 false的布爾值,’u0000′ 至 ‘u007f’ 之間的字符中時,將 p 包裝成 a 和 b 兩個對象時,能夠直接使用 a == b 判斷 a 和 b 的值是否相等。ide

A boxing conversion may result in an OutOfMemoryError if a new instance of one of the wrapper classes (BooleanByteCharacterShortIntegerLongFloat, or Double) needs to be allocated and insufficient storage is available.性能

5.1.7 章節闡述: ui

  1. 當內存空間不足以分配時,出現OutOfMemoryError; 
  2. 對於除 float、double外的的基本數據類型在自動裝箱時有緩存Cache; 
  3. 在float、double裝箱時,須要關注是不是NaN(Not-a-Number)

5.1.8 章節在關於拆箱的描述中: 若是爲null時,將拋出NullPointerException.this

Double:

    /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code double}. It is equivalent to the value returned by
     * {@code Double.longBitsToDouble(0x7ff8000000000000L)}.
     */
    public static final double NaN = 0.0d / 0.0;


Float:

   /**
     * A constant holding a Not-a-Number (NaN) value of type
     * {@code float}.  It is equivalent to the value returned by
     * {@code Float.intBitsToFloat(0x7fc00000)}.
     */
    public static final float NaN = 0.0f / 0.0f;

eg.

Integer aa = 127, bb = 127;
        System.out.println(aa == bb); //true  
        aa = 128;
        bb = 128;
        System.out.println(aa == bb); //false  --由於128超出範圍
        System.out.println(aa.equals(bb)); //true  

        Integer a = 10; //this is autoboxing
        Integer b = Integer.valueOf(10); //under the hood
        System.out.println(a == b); // true

        Float c = 0f / 0f;
        Float d = 0f;

        System.out.println(c == d); // false -- c是NaN
        System.out.println(c.isNaN()); // true
        System.out.println(d.isNaN()); // false

        Double e = 0d / 0d;
        Double f = 0d;

        System.out.println(e == f); // false -- e是NaN
        System.out.println(e.isNaN()); // true
        System.out.println(f.isNaN()); // false

Boolean、Byte、Short、Integer、Long、Character 的緩存機制

Integer

在 Java 5 中,爲 Integer 的操做引入了一個新的特性,用來節省內存和提升性能。整型對象在內部實現中經過使用相同的對象引用實現了緩存和重用。上面的規則適用於整數區間 -128 到 +127
這種 Integer 緩存策略僅在自動裝箱(autoboxing)的時候有用,使用構造器建立的 Integer 對象不能被緩存。
Java 編譯器把原始類型自動轉換爲封裝類的過程稱爲自動裝箱(autoboxing),這至關於調用 valueOf 方法!

Integer a = 10; //this is autoboxing
Integer b = Integer.valueOf(10); //under the hood

源碼以下:

在-128到127區間將取緩存中的,超出範圍後會new新的地址堆對象。

/**
     * Returns an {@code Integer} instance representing the specified
     * {@code int} value.  If a new {@code Integer} instance is not
     * required, this method should generally be used in preference to
     * the constructor {@link #Integer(int)}, as this method is likely
     * to yield significantly better space and time performance by
     * caching frequently requested values.
     *
     * This method will always cache values in the range -128 to 127,
     * inclusive, and may cache other values outside of this range.
     *
     * @param  i an {@code int} value.
     * @return an {@code Integer} instance representing {@code i}.
     * @since  1.5
     */
    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

IntegerCache

 Integer 類中一個私有的靜態類。

Javadoc 詳細的說明這個類是用來實現緩存支持,並支持 -128 到 127 之間的自動裝箱過程。最大值 127 能夠經過 JVM 的啓動參數 -XX:AutoBoxCacheMax=size 修改。 緩存經過一個 for 循環實現。從小到大的建立儘量多的整數並存儲在一個名爲 cache 的整數數組中。這個緩存會在 Integer 類第一次被使用的時候被初始化出來。之後,就可使用緩存中包含的實例對象,而不是建立一個新的實例(在自動裝箱的狀況下)。

實際上在 Java 5 中引入這個特性的時候,範圍是固定的 -128 至 +127。後來在 Java 6 中,最大值映射到 java.lang.Integer.IntegerCache.high,可使用 JVM 的啓動參數設置最大值。這使咱們能夠根據應用程序的實際狀況靈活地調整來提升性能。是什麼緣由選擇這個 -128 到 127 這個範圍呢?由於這個範圍的整數值是使用最普遍的。 在程序中第一次使用 Integer 的時候也須要必定的額外時間來初始化這個緩存。

/**
     * Cache to support the object identity semantics of autoboxing for values between
     * -128 and 127 (inclusive) as required by JLS.
     *
     * The cache is initialized on first usage.  The size of the cache
     * may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
     * During VM initialization, java.lang.Integer.IntegerCache.high property
     * may be set and saved in the private system properties in the
     * sun.misc.VM class.
     */

    private static class IntegerCache {
        static final int low = -128;
        static final int high;
        static final Integer cache[];

        static {
            // high value may be configured by property
            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;

            cache = new Integer[(high - low) + 1];
            int j = low;
            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() {}
    }

其餘緩存

Byte,Short,Long、Integer的緩存有固定範圍: -128 到 127,對於 Character緩存範圍是 0 到 127除了 Integer 能夠經過參數改變範圍外,其它的都不行。

tip1: 
    String 的 valueOf方法只有對boolean的處理返回字面量(字符串常量池), 其餘都是new新的!

    public static String valueOf(boolean b) {
        return b ? "true" : "false";


    }

tip2: 對於Byte而言值的範圍在[-128,127] 

byte佔一個字節空間,最高位是符號位,剩餘7位能表示0-127,加上符號位的正負,就是-127至+127,但負0不必,爲充分利用,就用負零表示-128(即原碼1000,0000)。(計算機轉補碼後存儲)

對於boolean類型: 提供靜態的2中枚舉值

public static Boolean valueOf(boolean b) {
        return (b ? TRUE : FALSE);
    }

ByteCache 緩存 Byte 、ShortCache 緩存 Short 、 LongCache 緩存 Long <三者源碼相似,>

private static class LongCache {
        private LongCache(){}

        static final Long cache[] = new Long[-(-128) + 127 + 1];

        static {
            for(int i = 0; i < cache.length; i++)
                cache[i] = new Long(i - 128);
        }
    }

CharacterCache 緩存 Character

private static class CharacterCache {
        private CharacterCache(){}

        static final Character cache[] = new Character[127 + 1];

        static {
            for (int i = 0; i < cache.length; i++)
                cache[i] = new Character((char)i);
        }
    }
 
eg. 在斷點單測時發現 都跳入了valueOf方法!
public static void main(String[] args) {
        Long a = 3L;
        Integer b = 4;
        Character c = 5;
        Byte d = 7;
        Short e = 1;
        System.out.println(a == Long.valueOf(a));
        System.out.println(b == Integer.valueOf(b));
        System.out.println(c == Character.valueOf(c));
        System.out.println(d == Byte.valueOf(d));
        System.out.println(e == Short.valueOf(e));
    }

運行的結果都爲true!

相關文章
相關標籤/搜索