變量與常量是一個Java程序組成的重要部分。
我們可以將變量與常量理解爲數據的載體,而從名稱上我們也可以看出二者的不同:
常量代表不能改變的數據值,而變量的值則存在可變性。
在我們回顧Java中的關鍵字的使用時,說道:被Java中的關鍵字final所修飾的變量,其值一經初始化,便不能再次進行賦值。該特性恰恰符合常量的定義。
- String var = "字符串變量";
- //java中,關鍵字final用於聲明數據常量
- final String CONSTANT = "字符串常量";
既然我們知道了變量與常量是作爲數據的載體使用;那麼,就如同我們如果使用一個杯子作爲載體,那麼其搭載的介質可能是水,咖啡,果汁等等一樣;
我們自然要了解Java中的變量與常量作爲數據載體,其搭載的數據究竟有哪些?
大體來說,Java的數據類型分爲:基本數據類型,對象數據類型以及數組,但數組實際也屬於對象。
所以,Java中的變量/常量就是用以作爲基本數據類型和對象數據類型的載體的。
對象數據類型的回顧需要結合一個關鍵的概念:類。
所以在這裏,我們先將變量和常量作爲切入點,首先來重新系統的總結一下Java中的8種基本數據類型的特性及使用。
總的來說,Java中的8種數據類型可以分爲三類:數字類型,字符類型和一種特殊的數據類型布爾型。
一、數字數據類型
數字數據類型共有6種,其中4種用於表示整數,2種用於表示浮點數。
首先需要明確的是:Java中的6種數字類型都是有符號數,也就是說它們都有正負之分。而具體又是如何區別表示正數與負數的呢?
我們知道所謂的“1”,“3”,“101”這樣的數,是我們日常生活中習慣使用的十進制數。
但在計算機中,所有數字都是以二進制數來表示的,也就是說,是一串由“0”和“1”組成的數字。
這樣的一串數字中,其最高有效位是用於表示符號的,就是所謂的符號位。
符號位爲“0”,代表是一個正數;符號位爲“1”,代表是一個負數。而剩餘位則用於表示值。
1.1、整數類型
Java中,用於表示整數的4種數字類型分別爲:byte(字節型)、short(短整型)、int(整型)、long(長整形)
我們說在計算機中,數字都是由二進制形式表示的,那麼自然的,其位數越多,可能的取值範圍就越大。
所以我們看到從byte到long,隨着所佔位數的增加,其取值範圍也就越大。
計算機中,一個字節等於8個比特位。而byte長度正是8位,這也是爲什麼它被取名爲字節型;
而剩下的short,int,long分別對應2個字節,4個字節和8個字節。
進制轉換:
我們剛剛已經說到了二進制和十進制,而在Java中,整數還有另外兩種進製表現形式,分別是:八進制和十六進制。
在瞭解進制轉換之前,我們先通過一段簡單的代碼瞭解一下Java中八進制和十六進制數的聲明形式是怎麼樣的:
- // 十進制定義形式
- int num_10 = 10;
- // 八進制定義形式,以“0”作爲前綴,表示定義的是一個八進制整數
- int num_8 = 012;
- // 十六進制定義形式,以“0x”作爲前綴,表示定義的是一個十六進制整數
- int num_16 = 0xef;
瞭解了不同進制的定義形式,我們就可以看一下進制之間的相互轉換了。首先我們應該知道,所謂進制,其實原理都是一樣的:
所謂二進制,就是指“逢二進一”,也就是說二進制中只可能存在“0”和“1”兩種可能值;
而所謂十進制,就是指“逢十進一”,也就是說只可能存在0-9的可能值;
那麼同樣的,八進制就是指“逢八進一”,所以只可能存在0-7的可能值;
同理的,十六進制就存在0-15的可能值。但傳統定義數字中,“9”已經是單位的最大可能值,所以十六進制中以英文字母a - f分別代表 10 - 15。
那麼,進制之間究竟是如何完成相互之間的轉換工作的呢?
1、二進制數、八進制數、十六進制數轉十進制數
有一個公式:二進制數、八進制數、十六進制數的各位數字分別乖以各自的基數的(N-1)次方,其和相加之和便是相應的十進制數。例如:
二進制數:0000-0110轉換爲十進制數:1*2的2次方+1*2的1次方+0*2的0次方=0+4+2+0=6,也就是說轉換爲十進制數的值爲:6。
2、十進制數轉二進制數、八進制數、十六進制數
方法是對應的的,即整數部分用除基取餘的算法,小數部分用乘基取整的方法,然後將整數與小數部分拼接成一個數作爲轉換的最後結果。
3、二進制數轉換爲八進制數或十六進制數
其原理很簡單:我們已經知道了八進制只有0-7的可能值,十六進制則只有0-15這的可能值。
而我們觀察到這樣一種情況,對於一個二進制的數來說:
如果只取一個有效位的數,所能能表達的最大數爲:1;
而取兩個有效位的數,所能表達的最大值則爲:“11”,也就是十進制的3;
取三個有效位的數,能表達的最大的數爲“111”,則是十進制的7;
而取四個有效位的數“1111”,則正是十進制的15.
由此我們發現:
如果將二進制數每三位取出,則正好能表示一個八進制的數;
而將二進制數每四位取出,則正好能表示一個十六進制數。
而事實上,二進制與八進制和十六進制的轉換原理也正是這樣的。
舉例來說,以二進制數:0000-1010爲例:
轉換爲八進制數爲:000/001/010,也就是12;
而如果轉換爲十六進制則爲:0000/1010,也就是a。
1.2、浮點數類型
正如數學中數字分爲整數和小數一樣,Java中也是一樣的。但Java不稱爲小數,稱爲浮點數。
而Java中,用於表示浮點數的兩種種數字類型分別爲:float(單精度浮點型)和double(雙精度浮點型)。
Java裏默認的浮點數形式是雙精度形式,也就是double。
所以在定義一個float時,必須加上後綴F(f):float f = 2.3F。
而定義double,後綴D(d)的添加則是可選的。
到了這裏,我們已經瞭解了Java中所有的數字類型。
之所以瞭解它們各自不同的特性,是爲了在實際編寫代碼的過程中,可以根據實際需求選取最合適的數據類型來定義自己的變量(常量)。
舉例來說:
如果想要表示全世界的人口數量,那麼可能選擇long型來表示更爲合適;
而如果要表示某個公司的職員每月的工資情況,那麼選用float可能更爲合適。
三、字符類型
Java中,另一種基本數據類型:char型,代表字符類型。
在開發中,可能經常需要存儲一些字符,如‘A’,‘c’等等。char型就是用於存儲單個字符的數據類型。
同時,char型數據也可以通過Unicode碼錶示字符;
簡單的來說,就是我們也可以通過在Unicode碼錶中有效的整數來表示一個字符。
其實很好理解,就像我們在小時候學習拼音的時候,可能都會接觸到“拼音字母學習表”一樣:
Unicode碼錶也是類似於這樣的一張字符編碼表,所謂編碼就是對錶中的每一個字符編排一個“號碼”。
這個號碼就像我們每個人的身份證,是獨特對應的關係,通過身份證號碼就可以查出我們每個人的信息。
到了這裏就不難理解了,就假設:我們以97表示一個字符,Java會根據該值到Unicode碼錶中進行查詢,然後發現號碼“97”對應的字符是"a"。
Unicode碼是用'\uxxxx'表示的。x表示的是16進制數值。
並且Unicode編碼字符是用16位無符號整數表示的。也就是說,Unicode碼錶共有0-65535的編碼值。
四、布爾類型
Java中一種特殊的數據類型,只有“true”和”false“兩種可能值。通常用於關係運算或條件判斷表達式返回的結果。
數據類型的轉換
Java自身是一門強數據類型語言,所以在遇到不同數據類型同時操作,就需要進行數據類型的轉換。
數據類型轉換需要滿足的最基本的要求,就是數據類型必須兼容。例如要將一個布爾型的數據轉換爲整數類型,肯定是不能成功的。
而在Java中,數據類型的轉換又分爲兩種:自動類型轉換和強制類型轉換。
所謂自動轉換就是指無需認爲做任何額外的工作,虛擬機會自動的完成對數據類型的轉換工作。
而強制轉換則是指我們必須人爲的進行聲明後,才能完成想要的數據類型轉換。
也就是說,自動數據類型轉換是隱式的轉換,而強制類型轉換則是顯式的轉換。
那麼首先來看一下自動類型轉換:
第一種情況:低位數的數據類型可以自動轉換爲高位數的數據類型。
- // 低位數的數據類型自動轉換爲高位數的數據類型
- byte b = 1;
- short s = b;
- int i = s;
- long l = i;
- float f = 1.5f;
- double d = f;
- /*
- * 另外,Java中整數的默認形式爲int型,
- * 所以下面的聲明形式實際也是:
- * 虛擬機自動完成了一次隱式的數據轉換工作
- */
- long num = 1000;
第二種情況:整數類型可以自動轉爲浮點數類型,但是這種轉換後的值可能會出現誤差。
第三種情況:字符類型可以自動轉換爲整型或長整形。這是因爲Java中char型數據也可以通過Unicode碼錶示,長度爲16位,所以也可以轉換爲長度更大的int和long型。
- char c1 = 'a';
- int i1= c1;
- char c2 = 'b';
- int i2 = c2 + 10;
- char c3 = 'c';
- long l = c3;
接下來,就是Java中的強制類型轉換:強制轉換的格式爲:(type)value。
第一種情況:對應於自動轉換,那麼當高位數的數據類型轉換爲低位數的數據類型時,就需要做強制轉換。
既然我們看到了”強制",那可能我們自然就會想到在這樣的轉換過程中,是不是存在一定的“風險”?
Java自身是一門嚴謹的編程語言,如果不存在風險,爲何還需要我們作人爲的"強制“性轉換呢?
而事實上也正是如此。我們首先應當瞭解,Java中對一個高位數數據轉換爲低位數數據類型時,實際上是在對二進制表現形式做有效位的截取。
我們知道一個二進制數的位數越多,其取值範圍也就越大,也就是說它的可能值越多。
這也就意味着,如果將一個高位數的數據類型轉換爲低位數的數據類型,那麼便可能發生:很多高位數能夠表達的可能值,低位數表達不了的情況。
這也正是其”風險“所在:轉換的過程中,可能造成數據丟失!
我們舉個例子來說:
假設我們有一個int型的變量,值爲128。相應的,我們將其轉換爲二進制表現形式就是:0000 0000 - 0000 0000 - 0000 0000 - 1000 0000。
如果我們要將其轉換爲byte類型。那麼byte類型的數據長度爲8位,所以我們進行有效位的截取後,值變爲了:1000 0000。
我們知道二進制數的最高有效位用以表示符號,所以這裏轉後的值的實際值變爲了十進制當中的-128。所以128在這個轉換中,值由原本的128變爲了-128。
既然高位數數據類型轉換低位數數據類型存在這樣的風險,那麼作爲一門健壯的語言,Java自然是不支持這樣的轉換的。
所以,爲我們了提供了(type)value這樣的強制轉換方式,我們這樣做的意義就在於,告訴編譯器,我瞭解這樣做可能承擔風險,但這個風險由我來承擔。
最後,我們通過代碼來驗證我們剛剛的轉換過程:
- int i1 = 127;
- byte b1 = (byte) i1;
- System.out.println("b1="+b1);
- int i2 = 128;
- byte b2 = (byte) i2;
- System.out.println("b2="+b2);
其運行的輸出結果爲:
b1=127
b2=-128
通過其結果恰恰驗證了我們提到的轉換過程。
因爲127本身在byte的取值範圍之內,所以強制轉換過後,數據仍然正確。但128超出了byte的取值範圍,所以在經過有效位的截取之後,值發生了變化,變爲了-128.
第二種情況:浮點數類型轉換爲整數類型需要進行強制轉換,因爲小數點後的數在轉換過程中會被丟棄
- double d = 128.123;
- //轉換後的值變爲了128
- int i = (int) d;
- System.out.println(i);
到此,我們以Java的變量(常量)爲切入點,又重新回顧了Java中8種基本數據類型的特點和使用。