(寫了很多Java 程序,也開發過很多Java項目,現在才決定要寫點Java相關的系列文章,因爲我對自己的文章沒有絕對的信心,都是開發過程中的經驗之談,再加上我自己 以前考過SCJP證書,所以希望寫點不誤導讀者的更加細節和詳細的文章出來,所以希望有讀者覺得有筆誤的話留我的Email地址給我,而且爲了不誤導讀 者,都使用了【草案】,謝謝大家的合作: [email protected] )
【以下講解都在 32bit 的系統中】
1.Java數據類型基本概念:
數 據類型在計算機語言裏面,是對內存位置的一個抽象表達方式,可以理解爲針對內存的一種抽象的表達方式。接觸每種語言的時候,都會存在數據類型的認識,有復 雜的、簡單的,各種數據類型都需要在學習初期去了解,Java是強類型語言,所以Java對於數據類型的規範會相對嚴格。數據類型是語言的抽象原子概念, 可以說是語言中最基本的單元定義,在Java裏面,本質上講將數據類型分爲兩種:簡單類型和複雜類型。
簡單類型: 簡單數據類型是不能簡化的、內置的數據類型、由編程語言本身定義,它表示了真實的數字、字符和整數。
複雜類型 :Java語言本身不支持C++中的結構(struct)或聯合(union)數據類型,它的複合數據類型一般都是通過類或接口進行構造,類提供了捆綁數據和方法的方式,同時可以針對程序外部進行信息隱藏。
2.Java中的 基本 類型:
1) 概念:
Java中的簡單類型從概念上分爲四種: 實數、整數、字符、布爾值 。但是有一點需要說明的是,Java裏面只有八種原始類型,其列表如下:
實數: double、float
整數: byte、short、int、long
字符: char
布爾值: boolean
復 雜類型和基本類型的內存模型本質上是不一樣的,簡單數據類型的存儲原理是這樣的:所有的簡單數據類型不存在“引用”的概念,簡單數據類型都是直接存儲在內 存中的內存棧上的,數據本身的值就是存儲在棧空間裏面,而Java語言裏面只有這八種數據類型是這種存儲模型;而其他的只要是繼承於Object類的複雜 數據類型都是按照Java裏面存儲對象的內存模型來進行數據存儲的,使用Java內存堆和內存棧來進行這種類型的數據存儲,簡單地講,“引用”是存儲在有 序的內存棧上的,而對象本身的值存儲在內存堆上的。
2) 詳細介紹:
Java的簡單數據 講解 列表如下:
int: int爲 整數 類型,在存儲的時候,用 4個字節 存儲,範圍爲 -2,147,483,648到2,147,483,647 ,在變量初始化的時候, int 類型的默認值爲 0 。
short : short 也屬於 整數 類型,在存儲的時候,用 2 個字節 存儲,範圍爲 -32,768 到 32,767 ,在變量初始化的時候, short 類型的默認值爲 0 ,一般情況下,因爲 Java 本身轉型的原因,可以直接寫爲 0 。
long : long 也屬於 整數 類型,在存儲的時候,用 8 個字節存儲,範圍爲 -9,223,372,036,854,775,808 到 9,223,372,036, 854,775,807 ,在變量初始化的時候, long 類型的默認值爲 0L 或 0l ,也可直接寫爲 0 。
byte : byte 同樣屬於 整數 類型,在存儲的時候,用 1 個字節 來存儲,範圍爲 -128 到 127 ,在變量初始化的時候, byte 類型的默認值也爲 0 。
float : float 屬於 實數 類型,在存儲的時候,用 4 個字節 來存儲,範圍爲 32 位 IEEEE 754 單精度 範圍,在變量初始化的時候, float 的默認值爲 0.0f 或 0.0F ,在初始化的時候可以寫 0.0 。
double : double 同樣屬於 實數 類型,在存儲的時候,用 8 個字節 來存儲,範圍爲 64 位 IEEE 754 雙精度 範圍,在變量初始化的時候, double 的默認值爲 0.0 。
char : char 屬於 字符 類型,在存儲的時候用 2 個字節 來存儲,因爲 Java 本身的字符集不是用 ASCII 碼來進行存儲,是使用的 16 位 Unicode 字符集,它的字符範圍即是 Unicode 的字符範圍 ,在變量初始化的時候, char 類型的默認值爲 'u0000' 。
boolean : boolean 屬於 布爾 類型,在存儲的時候不使用字節,僅僅使用 1 位 來存儲,範圍僅僅爲 0 和 1 ,其字面量爲 true 和 false ,而 boolean 變量在初始化的時候變量的默認值爲 false 。
3) 相關介紹:
在 Java 基本類型在使用字面量賦值的時候,有幾個簡單的特性如下:
【 1 】當整數類型的數據使用字面量賦值的時候,默認值爲 int 類型,就是直接使用 0 或者其他數字的時候,值的類型爲 int 類型,所以當使用 long a = 0 這種賦值方式的時候, JVM 內部存在數據轉換。
【 2 】當實數類型的數據使用字面量賦值的時候,默認值爲 double 類型,就是當字面兩出現的時候, JVM 會使用 double 類型的數據類型。
( * :以上兩點在轉型中進行詳細說明。)
【 3 】從 JDK 5.0 開始, Java 裏面出現了自動拆箱解箱的操作,基於這點需要做一定的說明:
對應原始的數據類型,每種數據類型都存在一個複雜類型的封裝類,分別爲 Boolean 、 Short 、 Float 、 Double 、 Byte 、 Int 、 Long 、 Character ,這些類型都是內置的封裝類,這些封裝類( Wrapper )提供了很直觀的方法,針對封裝類需要說明的是,每種封裝類都有一個 xxxValue() 的方法,通過這種方法可以把它引用的對象裏面的值轉化成爲原始變量的值,不僅僅如此,每個封裝類都還存在一個 valueOf(String) 的方法直接把字符串對象轉換爲相應的簡單類型。
在 JDK 5.0 之前,沒有存在自動拆解箱的操作,即 Auto Box 操作,所以在這之前是不能使用以下方式的賦值代碼的:
Integer a = 0; // 這種賦值方式不能夠在 JDK 1.4 以及以下的 JDK 編譯器中通過
但是 JDK 5.0 出現了自動拆解箱的操作,所以在 JDK 5.0 以上的編譯器中,以上的代碼是可以通過的,關於自動拆箱解箱我會另外用一篇 1.4 到 5.0 的升級加以詳細說明。
3.Java 中簡基本數據類型的轉型:
Java 中的簡單數據類型的轉換分爲兩種: 自動轉換和強制轉換
1) 自動轉換:
當一個較“小”的數據和較“大”的數據一起運算的時候,系統將自動將較“小”的數據轉換爲較“大”的數據,再進行運算。
在方法調用過程,如果實際參數較“小”,而函數的形參比較“大”的時候,除非有匹配的方法,否則會直接使用較“大”的形參函數進行調用。
2) 強制轉換:
將“大”數據轉換爲“小”數據時,可以使用強制類型轉換,在強制類型轉換的時候必須使用下邊這種語句:
int a = (int)3.14;
只是在上邊這種類型轉換的時候,有可能會出現精度損失。
關於類型的自動提升,遵循下邊的規則:
所有的 byte 、 short 、 char 類型的值將提升爲 int 類型;
如果有一個操作數是 long 類型,計算結果是 long 類型;
如果有一個操作數是 float 類型,計算結果是 float 類型;
如果有一個操作數是 double 類型,計算結果是 double 類型;
自動類型轉換圖如下:
byte -> short(char) -> int -> long -> float -> double
如果是強制轉換的時候,就將上邊的圖反過來
3) 轉換附加:
當兩個類型進行自動轉換的時候,需要滿足條件:【 1 】這兩種類型是兼容的,【 2 】目的類型的數值範圍應該比源轉換值的範圍要大。而拓展範圍就遵循上邊的自動類型轉換樹,當這兩個條件都滿足的時候,拓展轉換纔會發生,而對於幾個原始類型轉換過程,根據兼容性 boolean 和 char 應該是獨立的,而其他六種類型是可以兼容的,在強制轉換過程,唯獨可能特殊的是 char 和 int 是可以轉換的,不過會使用 char 的 ASCII 碼值比如:
int a = (int)'a';
a 的值在轉換過後輸出的話,值爲 97 ;
4.Java 中的高精度數:
Java 提供了兩個專門的類進行高精度運算: BigInteger 與 BigDecimal ,雖然 Java 原始變量都具有對應的封裝類型,但是這兩個變量沒有對應的原始類型,而是通過方法來提供這兩種類型的一些運算,其含義爲普通類型能夠做的操作,這兩個類型對應都有,只是因爲精度過大可能效率不夠高。至於這兩個類的具體操作可以參考 JDK 的相關 API 文檔。
5. 關於數據類型的一些技巧:(以下爲參考一篇原文文檔)
若要求精度的結果,儘量避免使用 float 和 double :
float 和 double 類型本身是爲了做科學運算,即執行二進制浮點運算而設計,但是卻不能提供完全精確的結果,所以在要求精度的數值中,避免使用 float 和 double , float 和 double 在貨幣運算中尤其不合適,要讓 float 和 double 精確表達 0.1 也是不可能的事。測試一下下邊這段代碼就明白了:
System.out.println(2.02-0.42);
結果是不是出乎意料,這個結果並不是偶然,而是 JVM 本身設計的目的決定的。而要解決這個問題,最好的辦法是使用 BigDecimal 、 int 或者 long 進行相關運算,特別是貨幣運算,使用 BigDecimal 代替 double 是一個很好的辦法。
BigDecimal 唯一的缺點在於: BigDecimal 沒有相對應的原始類型,所以在進行基本數值運算的時候,需要進行方法調用才能操作,這樣會使得和我們的編程習慣不相符合,若使用 int 和 long ,就需要進行簡單的封裝運算。
所以在要求精度答案的計算任務裏面,一般慎用 float 和 double ,如果在進行商務運算,並且要求四捨五入或者簡單的舍入行爲,使用 BigDecimal 可能更加方便。所以儘量避免在精度運算中使用 float 和 double ,特別是我們常用的貨幣運算。
5. 總結:
以上是開發過程中針對 Java 數據類型的一份總結,最後一個技巧是在一個商務系統運算的時候發現的,然後參考了網上的很多文檔,偶然在一篇 BLOG 中發現的,原文提倡在精度運算中儘量不用 float 和 double ,而關於 Java 的基本數據類型,上邊應該涵蓋了所有開發會用到的內容,還有一點就是在於幾個特殊值的比較,這裏沒有做說明,比如 Double.NaN == Double.NaN 輸出爲 false ,等等所有封裝類的特殊類型,沒有進行詳細說明。