Notes 20180509 : Java基本數據類型

  計算機就是個機器,這個機器由CPU、內存、硬盤和輸入輸出設備組成。計算機上運行着操做系統,操做系統提供對外的接口供各廠商和開發語言,開發運行在其上的驅動和應用程序。html

  操做系統將時間分紅細小的時間碎片,每一個時間碎片都單獨分配給一個應用程序(進程),而且頻繁的切換。只是由於時間碎片很細小,而且切換速度很快,因此看起來就好像雖有的應用程序都在同時執行同樣。java

  對於程序員而言,咱們寫程序基本不用考慮其餘應用程序,只用想好怎麼作本身的事情就OK了。不一樣的應用程序可以實現不一樣的功能。可是本質上計算機只會執行預先寫好的指令而已,這些指令也只是操做數據或者設備。所謂程序基本上就是告訴計算機要操做的數據和執行的指令序列(因此我在一篇文章中寫過程序=數據結構+算法),即對什麼數據作什麼操做。如讀文檔,就是將數據從磁盤加載到內存,而後CPU處理再將數據返回到內存,內存中的數據輸入到輸出設備。程序員

  基本上,全部的數據都須要先存放在內存中進行處理,程序的很大一部分工做就是操做在內存中的數據。數據在計算機內部都是以二進制存儲的,並無數據類型的概念。這對於程序員而言是很不方便處理的,爲了方便操做數據,高級程序語言引入了數據類型和變量的概念。數據類型對數據歸類、方便理解和操做,對於Java語言而言數據類型分爲基本數據類型和引用數據類型兩種,如圖4.1所示。在本章節中咱們就來認識一下Java中的數據類型;算法

 

圖4.1   Java數據類型安全

1.1 基本數據類型

  在Java中有8種基本數據類型來存儲數值、字符和布爾值。這些數據在計算機中或佔據不一樣的存儲空間或者是存儲不一樣類型的數據,下面咱們來了解一下;數據結構

1.1.1 整數類型

  整數類型用來存儲整數數值,即沒有小數部分的數值,也叫定點類型。能夠是正數、負數,也能夠是0(須要注意的是數學上的0.0和計算機中的0.0不一樣,數學中的0.0和0是相等的,可是在計算機中0.0和0屬於不一樣的數據類型,前者是浮點類型,然後者是int類型或者其它整數類型)。根據所佔內存的大小不一樣,能夠分爲byte、short、int和long 4種類型。他們所佔的內存和取值範圍如表4.2所示。整數默認的類型爲int型。整數類型是帶符號的數值類型。編碼

 

圖4.2   整數類型(1個字節是8位)spa

1.1.1.1.byte型

  byte類型是有符號數值,使用byte關鍵字來定義byte型變量,能夠一次定義多個變量並對其進行賦值,也能夠不進行賦值。byte型是整型中分配內存空間最少的,只分配1個字節,取值範圍也是最小的,只在-128~127之間,在使用時必定要注意,以避免數據溢出產生錯誤。操作系統

【例4.1】定義byte型變量,並對其進行簡單賦值操做,驗證其幾點要素;設計

package cn.basic.datatype.bytes; public class BytePractice{ public static void main(String[] args){ byte a = 45 , b = 127 , c ; System.out.println(a+b);//整數類型的默認類型爲int,因此再給byte類型進行運算時會先將其轉換爲int類型,而後進行運算 //System.out.println(c); 咱們聲明瞭變量卻未給其賦值,這裏會報未初始化變量,局部變量必須賦值
        /* b = 128 ; byte類型的內存空間爲1字節,取值範圍爲-128-127,因此這裏會報損失精度的問題,可是仍然能夠經過強制轉型來解決,結果就是輸出與實際數值不符,這是精度損失形成的 System.out.println(b);*/ } }

注意:成員字段若是沒有初始化,那麼編譯時會自動初始化爲默認值。但局部變量若是沒有初始化則會在編譯時報錯「變量未經初始化」;這和類的加載是有關係的,關於類的加載,咱們在之後的JVM中再作敘述。

1.1.1.2.Short型

  Short型是短整型,使用short關鍵字來定義short型變量,能夠一次定義多個變量並對其賦值,也能夠不進行賦值。系統給short型在內存中分配2個字節,取值範圍也比byte大得多,在-32768~32767之間,雖然取值範圍變大,但仍要注意溢出。

【例4.2】定義short型變量

short a = 23 ;   //定義short型變量a、b、c,並賦值給a、b

1.1.1.3.int型

  int型即整型,使用int關鍵字來定義int型變量,能夠一次定義多個變量並對其賦值,也能夠不進行賦值。int型變量取值範圍很大(4個字節),在-2147483648~2147483647之間,足夠在通常狀況下使用,因此是整數變量中應用最普遍的。int類型也是整數類型的默認類型。這意味着整數類型若是不作說明,那麼會自動轉換爲int類型。

【例4.3】定義int型變量

int a = 23 , b = 78 ;   ////定義int型變量a、b、c,並賦值給a、b

1.1.1.4.long型

  long型即爲長整形,使用long關鍵字來定義long型變量,能夠一次定義多個變量並對其進行賦值,也能夠不進行賦值。而在對long型變量進行賦值時結尾必須加上「L」或「l」(由於I和i的大寫類似,因此咱們通常使用L,便於閱讀。),不然將不被認爲是long型,而會被默認做爲int型處理,這時可能會出現溢出內存的錯誤,以下圖就是一個溢出的錯誤。因此當數值過大超過int型範圍時就用long型,系統分給long型8個字節,取值範圍更大,在-9223372036854775808~9223372036854775807之間。

【例4.4】定義long型變量,並對其進行一些分析;

package cn.basic.datatype.longs; public class LongPractice{ public static void main(String[] args){ long a = 3890 , b;     //當咱們定義一個變量時若是他的數值超過int的範圍,卻又不對其進行末尾強制, //b = 922337203685477 ; 那麼程序會將其當作int處理,則會發生錯誤,提示超出範圍 //System.out.println(b); 提示咱們數值過大
 System.out.println(a); b = 922337203685477L; System.out.println(b); b = 922337203685477l; System.out.println(b); //b = 922337203685477 L; 咱們在定義long型變量時要注意,初始化的後面緊跟"L"或"l",不能有空格的存在,不然會提示錯誤
 System.out.println(b); } }

咱們在定義long型數據時末尾最好加L,由於l和1是很差區分的;

上面的四種整數類型在Java程序中有3種表示形式,分別爲十進制、八進制、和十六進制。

【例4.5】整數的各型運算

package cn.basic.datatype.integer; public class IntegerPractice{ public static void main(String[] args){ byte a = 127 ; short b = 3276 ; int c = 214748364 ; long d = 21474836423444L ; long resultL = a + b + c + d ; //int resultD = a + b + c + d ;當一個高精度的數據類型向低精度轉換時,會報可能損失精度的錯誤 //int dd = (int)d;
        int dd = new Long(d).intValue(); int resultD = a + b + c + dd ; System.out.println("結果爲"+resultL); System.out.println("結果爲"+resultD); } }

 

1.1.2 浮點類型

  在計算機系統的發展過程當中,曾經提出過多種方法表示實數,可是到目前爲止使用最普遍的是浮點表示法。相對於定點數而言,浮點數利用指數使小數點的位置能夠根據須要而上下浮動,從而能夠靈活地表達更大範圍的實數。如上面的4中整數類型都是屬於定點類型。浮點類型表示有小數部分的數字。Java語言中浮點類型分爲單精度浮點類型(float)和雙精度浮點類型(double),它們具備不一樣的取值範圍,如圖所示。浮點型默認的類型爲double。

1.1.2.1 float型

  float型即爲單精度浮點型,使用float關鍵字來定義float型變量,能夠一次定義一個或多個變量並對其進行賦值,也能夠不進行賦值。在對float型進行賦值時末尾必須加上「f」或「F」,若是不加,系統會將其默認做爲double型來處理,float型的取值範圍在1.4E-45~3.4028235E38之間。

【例4.6】對float型進行定義;

package cn.basic.datatype.floats; public class FloatPractice{ public static void main(String[] args){ Float a = 1.4E-45F ; System.out.print(a); } }

1.1.2.2 double型

  double型即雙精度浮點型,使用double關鍵字來定義double型變量,能夠一次定義多個變量並對其進行賦值,也能夠不進行賦值。在給double型賦值時,可使用後綴「D」或「d」明確代表這是一個double類型數據,但加不加並無硬性要求,能夠加也能夠不加,double型變量的取值範圍在4.9E-324和1.2976931348623157E-308之間。

  單精度和雙精度的區別咱們會專門在一篇涉及精度的文章中講解。

【例4.6】定義一個double型變量和float型變量,並對它們進行賦值、運算和輸出;

package cn.basic.datatype.doubles; class DoublePractice{ public static void main(String[] args){ double a = 987.987123456789012D , b = 789.789879887918799d ; double c = 68.8978978977 ; float aa = 987.987123F ;        //當咱們定義一個float型變量卻又不對其進行末尾"F"或"f",那麼會提示錯誤可能損失精度
        float d = 987.987123456789012F ; float e = 987.987153456789012F , f = 987.987144456789012f ; System.out.println(a+"和"+b) ; System.out.println(c) ; System.out.println(aa+"和"+d+"和"+e+"和"+f) ; } }

 

1.1.3 字符類型

  在Java的基本數據類型中,咱們最難以說清楚的只怕就是char類型了,固然不少開發人員可能不引覺得然,認爲char不就是單引號括起來的一個字符嗎?其實否則,char表明一個字符,但是這個字符倒是要存儲到計算機中的,這就牽涉到了編碼的問題(計算機只能表示數值類型的數據)。Java是使用Unicode做爲默認編碼的,要想真正弄清楚char,那麼咱們須要先從Unicode編碼講起。

  瞭解了Unicode,咱們就明白了在Java中爲何使用Unicode做爲默認的編碼集,Char型即字符類型。使用char關鍵字進行聲明,用於存儲單個字符,在定義字符型變量時,要用單引號‘’括起來。如‘s’表示一個字符,且單引號中只能有一個字符,多了就不是字符類型,而是字符串類型,須要用雙引號進行聲明。char類型描述的是UTF-16編碼中的一個代碼單元(這也就是爲何char須要兩個字節的存儲空間了)。

  與C、C++語言同樣,Java語言也能夠把字符做爲整數對待,因爲Unicode編碼採用無符號編碼,能夠存儲65536個字符(0x0000~0xffff),因此Java中的字符幾乎能夠處理全部國家的語言文字。若想獲得一個0~65536之間的數所表明的Unicode表中相應位置上的字符,也必須使用char型顯式轉換。

  注意:Java使用Unicode編碼,可是要注意這裏面的區別,Unicode是一個很大的字符編碼集,分爲多層,而char使用的是UTF-16編碼,因此纔有65536這一說。

  在字符類型中有一種特殊的字符,以反斜線「\」開頭,後跟一個或多個字符,具備特定的含義,不一樣於字符原有的意義,叫作轉義字符,Java中的轉義字符以下所示。

 

注意:轉義字符也是字符,因此在使用時一樣要加‘’單引號。

【例4.7】建立一個類CharPractice,實現將Unicode表中某些位置上的一些字符以及一些字符在Unicode表中的位置在控制檯上面輸出。

package cn.basic.datatype.ch; class CharPractice{ public static void main(String[] args){ int a = 'd' , aa = 97 ; char b = 97 , c = 'a' ; char d = '\\' , e = '\b' , f = '\n' , g = '\u2605' , h = '\u0052' ; //轉義字符
        char i = '\u4e08'; System.out.println(a+"和"+aa+"和"+b+"和"+c) ; System.out.println(d+"和"+e+"和"+"和"+g+"和"+h) ; System.out.println(f) ; System.out.println(i); } }

注意:char描述的只是UTF-16的一個代碼單元,不能徹底表示Unicode中的全部字符.因此咱們在程序中建議使用String.

1.1.4 布爾類型

布爾類型又稱邏輯類型,只有「true」和「false」兩個值,分別表明布爾邏輯中的「真」和「假」,使用boolean關鍵字來聲明布爾類型變量,一般被用在流程控制中做爲判斷條件。

【例4.8】聲明一個布爾變量,並對其進行輸出;

     boolean abc = true , cba = false ; System.out.println(abc+"仍是"+cba) ; if(abc)System.out.println("真就是真!"); else{ System.out.println("假就是假!"); } if(cba)System.out.println("真就是真!"); else{ System.out.println("假就是假!"); }

 

1.2 引用數據類型

  Java中除了提供基本數據類型外,還提供了引用數據類型,講起引用數據類型就不得不說面向對象了;

  Java是一種面向對象的設計語言,它將具備相同屬性和行爲的一類事物封裝進類中,咱們研究的時候只有研究該類的一個抽象個體,這個個體就是對象。對象也是一種數據類型,在內存中分配內存空間,經過引用來訪問,這就是引用數據類型,關於引用詳見揭祕對象。

  Java中引用數據類型和基本數據類型的不一樣就在於存儲的位置和所能實現的功能。基本數據類型根據做用域分爲運行時常量池和局部變量表中,而引用類型倒是都存放在堆中,基本數據類型只是用來做爲運算的數據,而對象則是類的一個實例,其中包含了類中數據的一份copy和功能的實現。所能實現的功能也截然不同。關於引用類型咱們認識到這裏也就能夠了。

1.3 數據類型轉換

  類型轉換是將一個值從一種類型更改成另外一種類型的一個過程。例如,能夠將String類型數據「457」轉換爲一個數值型,並且能夠將任意類型的數據轉換爲String類型。數據類型轉換有不少種,這裏咱們只講解基本數據類型的轉換,至於基本數據類型和引用數據類型的轉變(自動拆裝箱),後邊咱們會在其它文章中敘述。

  基本數據類型的轉換若是從低精度數據類型向高精度數據類型轉換,則永遠不會溢出,而且老是成功的;而把高精度數據類型向低精度數據類型轉換時則必然會提示有精度損失,有可能失敗(取決於高精度數據精度是否超過了低精度的最高精度位)。

  數據類型轉換有兩種方式,即隱式轉換和顯示轉換。

1.3.1 隱式數據類型轉換

  從低精度類型向高精度類型的轉換,系統將會自動執行,程序員無需進行任何操做。這種類型的轉換稱爲隱式轉換,也叫自動類型轉換。下列基本數據類型會涉及數據轉換,不包括邏輯類型和字符類型。這些類型按精度從低到高排列順序爲byte < short < int< long < float < double。

注意:byte,short,char之間不會互相轉換,他們三者在計算時首先會轉換爲int類型,有多種類型的數據混合運算時,系統首先自動的將全部數據轉換成容量最大的那一種數據類型,而後再進行計算。

【例4.9】將下面int型數據轉換爲float型數據;

int x = 50 ; float y = x ; System.out.println(y) ; //輸出的結果爲50.0

隱式數據類型轉換也須要遵照必定的規則,那麼在運算時各個類型之間要怎麼轉換呢?各類狀況下數據類型之間轉換通常遵照以下規則。

 

【例4.10】建立一個類ImplicitConvertPractice,在這個類中聲明各類基本數據類型變量,而後進行一系列操做,查看結果。

複製代碼
package cn.basic.datatype.change; class ImplicitConvertPractice{ public static void main(String[] args){ byte a = 127 ; short b = 37 ; char ch = 'a' ; System.out.println(ch) ; int xy = a + b + ch ; System.out.println("當byte short和char一塊兒運算時,他們會先轉換爲int型在進行計算,由於整數類型默認爲int型: " + xy) ; int x = 50 ; long c = 922068547 ; float y = x ; double d = 92233747.9798698 ; System.out.println("當byte型和short型在一塊兒運算時其運算結果爲:" + (a+b) ) ; System.out.println("當byte、short型和int型在一塊兒運算時其運算結果爲:" + (a+b+x)) ; System.out.println("當byte、short、int型和long型在一塊兒運算時其運算結果爲:" + (a+b+c+x)) ; System.out.println("當byte、short、int、long型和float型在一塊兒運算時其運算結果爲:" + (a+b+x+c+y)) ; System.out.println("當byte、short、int、long、float型和double型在一塊兒運算時其運算結果爲:" + (a+b+c+x+y+d)) ; } }
複製代碼

  並非全部的隱式轉換都是安全的,隱式轉換也要注意精度的問題,若是咱們在運算過程當中低精度向高精度轉換時超出了高精度的取值範圍,那麼也會形成精度損失的問題,以下代碼演示

    /**
     * 隱式轉換也不近是安全的
     */
    @org.junit.Test
    public void test1(){
        int i = Integer.MAX_VALUE - 3;
        byte b = 4;
        int a = i + b;
        System.out.println("i="+i+"  b="+b+"  a="+a);
    }

咱們看到最後的結果和預想的不一致,這就是運算過程當中超出最高精度,形成損失的結果。

1.3.2 顯式數據類型轉換

  當把高精度的變量賦值給低精度的變量時,必須使用顯式類型轉換(又叫強制類型轉換)。語法以下:

  (低精度類型名)要轉換的值

  當咱們把一個高精度想一個低精度轉換時,不可超出這些變量取值範圍,不然會發生數據溢出的現象,此時會形成數據丟失,因此在使用強制類型轉換時,必定要加倍當心,不要超出變量的取值範圍,不然就得不到的想要結果。好比咱們進行一次byte和short之間的顯示轉換

byte a = 127 ; short b = 516 ; byte ab = (byte)b ; //因爲short的範圍超出了byte的127因此發生溢出,數據損失 System.out.println(ab) ; //結果爲4

原理以下:

 

boolean類型不能被轉換爲其餘類型,反之亦然;

【例4.11】咱們建立一個類ExplicitConvertPractice,聲明各類數據類型,並對其進行轉換操做;

複製代碼
package cn.basic.datatype.change; class ExplicitConvertPractice{ public static void main(String[] args){ byte a = 127 ; short b = 516 ; byte ab = (byte)b ; byte abc = (byte)(b - a - a - a - a) ; char ch = 'a' ; System.out.println(ch) ; int xy = a + abc + ch ; System.out.println("當byte short和char一塊兒運算時,他們會先轉換爲int型在進行計算,由於整數類型默認爲int型: " + xy) ; System.out.println("當數據範圍過大時會發生數據損失: "+ ab ) ; //顯示轉換數據丟失 System.out.println("當數據範圍合適時顯示轉換: "+ abc ) ; int x = 50 ; double d = 92247.8698 ; int bx = (int)(d - x) ; System.out.println("當double型和int型在一塊兒強制轉換時結果爲爲:" + bx ) ; boolean boo = false; //System.out.println((int)boo);  } }
複製代碼

【例4.12】:分析System.out.println(‘a’)與System.out.println(’a’+1) 的區別;byte b1=3,b2=4,b;    b=b1+b2;      b=3+4;  哪句是編譯失敗的呢?爲何呢?

複製代碼
class QuestionPractice{ public static void main(String[] args){ char a = 'a' ; System.out.println('a') ;//由於字符類型沒有參與運算,因此仍以字符類型輸出  System.out.println(a); System.out.println('a'+1) ;//字符類型和一個常量進行運算,字符類型和常量會都先轉換爲int類型,而後運算 byte b1 = 3 , b2 = 4 , b3 , b4 ; // b3 = b1 + b2 ; b1和b2是變量,由於變量的值會變化,不肯定具體的值,因此默認使用int類型進行存儲,他會先自動轉換爲int型,計算結果爲int型,而b3是byte型,是強制轉換, b3 = (byte)(b1 + b2) ; b4 = 3 + 4 ; //3和4都是常量,因此java在編譯時期會檢查該常量的和是否超出byte類型的範圍。若是沒有能夠賦值。  System.out.println(b3); System.out.println(b4); } }
複製代碼

分析:當咱們聲明一個字符變量,並對它進行輸出時,那麼咱們這是輸出的就只是一個字符,當咱們對着個字符比變量實現運算輸出時,那麼這時字符會先轉換成int型而後計算,結果以int型輸出;

1.4 計算機中的默認值

  咱們知道成員變量是能夠只聲明不賦值的,可是局部變量卻必須聲明並賦值才能使用,那麼這是爲何呢?這其實和類的加載有關係。關於類的加載,我放在後面JVM中講解;這裏咱們只看一下各類數據類型在類加載後的默認值。

複製代碼
package basic.value; public class Test { public int i;//全部數值類型默認初始化爲0 public static byte bb; public final byte bbb = 45;//成員若是被final修飾,那麼意味着是常量,此時必須賦值 char ch; short s; long l; float f; double d;//浮點類型默認是0.0 boolean b;//布爾默認false public static void main(String[] args) { Test test = new Test(); System.out.println(bb);//靜態方法中能夠直接調用靜態,非靜態只能初始化後才能加載  System.out.println(test.s); System.out.println(test.i); System.out.println(test.l); System.out.println(test.ch); System.out.println(test.f); System.out.println(test.d); System.out.println(test.b); } }
複製代碼

  這裏沒有列出引用類型,可是引用類型若是沒有賦值也是有默認值的,引用類型是null;

多學一點:精度問題

  在上文咱們幾回說到了精度的損失問題,這裏我特意總結了一篇精度損失的問題來探討這個問題,能夠做爲一家之言幫助理解;

相關文章
相關標籤/搜索