變量與常量是一個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種基本數據類型的特點和使用。
- 前言
- 第一個專欄《重走J2SE之路》,你是否和我有一樣的困擾?
- 磨刀不誤砍材工 - 環境搭建(為什么要配置環境變量)
- 磨刀不誤砍材工 - Java的基礎語言要素(定義良好的標示符)
- 磨刀不誤砍材工 - Java的基礎語言要素(關鍵字)
- 磨刀不誤砍材工 - Java的基礎語言要素(注釋-生成你自己的API說明文檔)
- 磨刀不誤砍材工 - Java的基礎語言要素(從變量/常量切入,看8種基本數據類型)
- 磨刀不誤砍材工 - Java的基礎語言要素(運算符和表達式的應用)
- 磨刀不誤砍材工 - Java的基礎語言要素(語句-深入理解)
- 磨刀不誤砍材工 - Java的基礎語言要素(數組)
- 換一個視角看事務 - 用"Java語言"寫"作文"
- 牛刀小試 - 淺析Java的繼承與動態綁定
- 牛刀小試 - 詳解Java中的接口與內部類的使用
- 牛刀小試 - 趣談Java中的異常處理
- 牛刀小試 - 詳解Java多線程
- 牛刀小試 - 淺析Java集合框架的使用
- 牛刀小試 - Java泛型程序設計
- 牛刀小試 - 詳細總結Java-IO流的使用