相關面試題
我們從學習Java開始,很快就會遇到 Java中的數據類型 這個問題。關於數據類型,對於初學者來説,很容易記混,因為Java中的數據類型劃分的有點多。所以在招聘初級程序員時,面試官就會經常在這一塊出一些題目,對求職者進行基礎語法方面的考核。常見的數據類型相關的面試題如下:
請説一下Java中有哪些數據類型?
Java中有哪些基本數據類型?
基本數據類型的取值範圍是多大?
Java的2個字節佔多少位?
int佔幾個字節?
數據類型之間怎麼進行轉換?
......
當然對於上面這些面試題,並不一定就這麼問,很多時候面試官可能會把題幹進行修改,但考察的內容其實還是這些內容。總之,萬變不離其宗,Java裏的知識點就那些東西,再怎麼問,也都是這些內容。
本篇文章會帶大家來複習Java中的數據類型,這些內容一般都是以記憶為主!
一. 題目分析
以上這些題目,其實都是圍繞着Java中的數據類型來進行提問的,考察的重點就是求職者對數據類型的掌握情況。因為Java中數據類型分類較多,初學者容易記混,並且在數據類型這一塊又涉及到類型轉換,開發時有可能會因為類型轉換導致一些bug。另外我們在編寫代碼時,不同的變量也應該選擇合適的數據類型,這樣有利於優化內存分配。 所以面試官針對這些來提問,目的就是在考察求職者的語言基礎是否紮實。
二. Java中的數據類型
我們在接觸任何一種編程語言時,都會存在對數據類型的認識,有複雜的,也有簡單的。這些數據類型都需要我們在學習初期去了解和掌握,所以各位請跟着 壹哥 來看看關於數據類型的知識吧。
- 靜態類型和強類型
因為Java語言是 靜態類型的(statical typed) , 也就是説Java中的所有變量和表達式的類型,在編譯時就已經完全確定了。所以我們在使用變量時,必須先聲明其類型,即在創建的那一刻就已經確定好了該變量的類型。在後面的使用中,你只能將這一指定類型的數據賦值給該變量,如果強行將其他不相干類型的數據賦值給它,就會引發錯誤。比如一旦聲明瞭一個int類型的變量,那麼之後就只能將int類型的數據賦值給它,否則就會引發錯誤。
由於Java是靜態類型statical typed的語言,這也就導致了Java是 強類型(Strong typed) 的語言,因為語言的強弱體現在對類型的檢查嚴格與否上。 弱類型語言對於變量類型的檢查比較寬鬆,容忍隱式類型轉換這種事情的發生,強類型則反之。所以強類型意味着每個變量都必須具有一種類型,每個表達式也都必須具有一種類型,並且每種類型都是有嚴格定義的。類型限制了該變量可以持有存儲哪類值,表達式最終產生什麼類型的值,同時也限制了這些值可以進行的操作類型以及操作的具體方式。所有的賦值操作,無論是顯式的、還是在方法調用中通過參數傳遞的,都要進行類型的兼容性檢查。
- 數據類型概念
現在經過上面壹哥對靜態類型和強類型概念的介紹後,我們就可以很好的理解數據類型的概念了。
所謂的數據類型,在計算機語言裏面,我們可以把它理解成是針對內存位置的一種抽象的表達方式。簡單的來説,數據類型就是對數據的一種分類,根據每種數據各自的特點進行類別的劃分,每種數據類型都與其他類型不同。 舉個栗子:我們可以把不同的數據類型理解為存儲在不同箱子裏的不同類別的內容,有的箱子裏只能裝固體,有的箱子裏只能裝液體,有的箱子裏只能裝氣體......這些箱子會存放在不同的地方,裏面的東西也不能混裝,每個箱子裏的東西也都屬於不同的分類。
- 數據類型分類
在Java裏面,整體上把數據類型分成了兩大類:基本類型(primitive types) 8個 和 引用類型(reference types) 5個,我們來看一張完整的分類圖,如下所示:
接下來我會對基本類型和引用類型分別進行介紹。
3.1 基本類型
基本類型 是Java中預定義的類型,有相應的保留關鍵字來表示,具有明確的取值範圍和數學行為, 表示了真實的數字、字符和整數。基本類型的數據都是單個值,不是複雜的對象,所以基本類型並不是面向對象的,這主要是出於效率方面的考慮。但同時Java中也為基本類型提供了對應的對象版本,即基本類型的包裝類(wrapper)。我們可以直接使用這些基本類型,也可以使用基本類型的構造數組或者其他自定義類型。
基本類型 包括布爾(boolean)類型、數值類型(numeric types),數值類型又分為 整型(integer types) 和 浮點型(floating-point type) 。整型有5種:byte、short、int、long、char(char本質上是一種特殊的int);浮點類型有float和double。所以基本數據類型分類如下:
byte、short、int、long、float(單精度)、double(雙精度)、char、boolean
基本類型具體信息表:
3.2 引用類型
引用類型(The value of reference types are references to objects)中的引用,一般是指某個對象的內存地址,其中對象是動態創建的類實例或者動態創建的數組。另外Java語言本身不支持C++中的結構體(struct) 或聯合體(union) 等數據類型,這種複合數據類型一般都是通過類或接口進行構造 。 引用數據類型分類如下:
類、接口、數組、枚舉、註解
3.3 關於null值
另外還有一個特殊的值null,我這裏再給各位解釋一下。null是一種特殊的type,但你不能聲明一個變量為null類型,null type的唯一取值就是null。 null可以賦值給任意的引用類型或者轉化成任意的引用類型。我們在開發時,一般是把null當做常量字面值,這個字面值可以賦值給任意的引用類型。
- 基本類型與引用類型的區別
不論是基本數據類型還是引用類型,他們都會先在棧中分配一塊內存。對於基本類型來説,這塊內存區域中包含的是基本類型的具體數據內容;對於引用類型來説,這塊內存區域中包含的是指向真正內容的指針,而真正的內容則被手動的分配在了堆中。
三. 基本類型的取值範圍
- 基本類型取值範圍
回顧了Java中的數據類型之後,我們再來複習一下基本類型的取值範圍大小。我們知道,所有的基本數據類型都有固定的存儲範圍和所佔有的內存空間大小,且不受具體操作系統的影響,以保證Java 程序的可移植性。每種數據類型所佔的內存空間大小如下:
byte: 1個字節,取值範圍 -128 到 127
short: 2個字節,取值範圍 -32768 到 32767
int: 4個字節,取值範圍 -2147483648(-2的31次方) 到 2147483647(2的31次方-1)
long: 8個字節,取值範圍 -9223372036854775808(-2的63次方) 到 9223372036854775807(2的63次方-1)
float: 4個字節,取值範圍 -3.40E+38 到 +3.40E+38 有效位數7-8位
double: 8個字節,取值範圍 -1.79E+308 到 +1.79E+308 有效位數15-16位
char: 2個字節,取值範圍 0-65535,共65536個字符
boolean: 不確定,取值範圍 true、false
基本類型取值範圍詳情表:
所以從上表中,我們就可以知道, Java中的 int 佔了4個字節32位。
- 各基本類型大小關係
另外我們還可以用下圖展示各基本類型按取值範圍大小的對比關係:
四. 基本類型之間的轉換
- 類型轉換
在Java中,將一種類型的值賦給另一種類型是很常見的,在這個賦值過程中有可能會進行類型的轉換,轉換分為自動轉換和強制轉換。自動類型轉換(隱式轉換)無需進行任何操作,而強制類型轉換則需要顯式轉換,即需要使用強制轉換操作符(type) 。
注意:
boolean類型與其他所有的7種類型都不能進行類型轉換,而其他7種基本類型彼此之間都可以進行轉換,但可能會出現精度損失或者其他的一些變化。
- 自動轉換
2.1 自動轉換時機
那麼什麼時候會進行自動轉換呢?
一般當一個較"小"的數據與一個較"大"的數據一起運算時,系統會自動將"小"數據轉換成"大"數據,再進行運算,這時就發生了自動轉換。
首先我們將7種類型按從小到大的順序排列一下:
byte < (short=char) < int < long < float < double
這裏我們所説的"大"與"小",並不是指佔用的字節有多少,而是指表示值的範圍大小。
在上面的7種類型之間,如果數據類型是從小轉換到大,可以進行自動轉換, 自動轉換時會發生擴寬(widening conversion) ;而從大到小,必須進行強制轉換;short和char兩種類型之間也必須強制轉換。 這是因為較大的類型(如int) 要保存較小的類型(如byte),內存總是足夠的,不需要強制轉換。我們直接將整型字面值(常量)賦值到byte、short、char、long時,其實也是自動進行了類型轉換。比如下面的源碼:
//“小”轉“大”,自動轉換
byte b = 100;
int i;
i = b;
System.out.println("i=" + i);
//“大”轉“小”,強制轉換
int i;
float f = 20000f;
i = (int) f;
System.out.println("i=" + i);
//short與char之間需要強制類型轉換
short s = 100;
char c = 90;
s=(short)c;
System.out.println("s="+s);
2.2 自動轉換時的精度損失
除了以下幾種情況可能會導致精度損失以外,其他的轉換都不會出現精度損失。
int--> float
long--> float
long--> double
float -->double without strictfp
除了可能的精度損失外,自動轉換時不會出現任何運行時異常。
- 強制轉換
3.1 強制轉換語法
如果要把"大"的轉成"小"的,或者在short與char之間進行轉換,就必須進行強制轉換。這也被稱作縮小轉換(narrowing conversion),這是因為必須顯式地使數值變得更小 以適應目標類型。嚴格地説,將byte轉為char不屬於縮小轉換narrowing conversion,因為從byte到char的過程其實是byte-->int-->char,也就是既有擴寬操作widening,也有縮小操作narrowing。強制轉換時需要採用轉換操作符(目標基本類型),格式如下:(target-type) value
//強制轉換案例
int x=300;
byte y;
y = (byte)x;
3.2 強制轉換的問題
另外強制轉換除了可能的精度損失外,還可能使模(overall magnitude)發生變化。即如果整數的值超出了byte所能表示的範圍,結果將對byte類型的範圍取餘數。例如a=257超出了byte的[-128,127]的範圍,所以會將257除以byte的最大範圍(256),然後得到餘數b=1。需要注意的是,當a=200時,此時除去256取得的餘數應該為-56,而不是200。
//強制轉換時模發生了變化
int a = 257;
byte b;
b = (byte) a;
System.out.println("b=" + b);//b=1
//a=200,餘數=-56
int a = 200;
byte b;
b = (byte) a;
System.out.println("b=" + b);//-56
將浮點類型賦給整數類型的時候,會發生截尾(truncation),也就是會把小數的部分去掉,只留下整數部分。 此時如果整數超出目標類型範圍,一樣會對目標類型的範圍取餘數。
//浮點賦值給整形,會截尾
float f=100.58f;
int i;
i=(int)f;
System.out.println("i="+i);//100
強制轉換時可能會導致溢出或精度的丟失。
3.3 表達式中數據類型的自動提升
我們表達式中可能會有+、-、*、/等各種操作符,在執行這些表達式時,則可能會發生數據類型的自動提升,有以下規則:
所有的byte、short、char型的值將被提升為int型;
如果有一個操作數是long型,計算結果是long型;
如果有一個操作數是float型,計算結果是float型;
如果有一個操作數是double型,計算結果是double型。
//表達式中的類型自動提升
byte b;
b = 10;
//因為此時b已經進行了類型提升,所以如果這裏不進行強制類型轉換則會報錯
//b=b*2;
//此時必須進行強制類型轉換
b=(byte)(b*3);
System.out.println("b="+b);//b=30
//類型提升為long
int i=400;
long l=500;
//這樣會報錯
//int x=i+l;
//這樣沒問題
long x=i+l;
System.out.println("x="+x);//x=900
五. 結論
至此,壹哥 就給大家梳理出了 “Java中數據類型” 相關面試題的答案,我們再看看前文中提到的面試題!
然後我再梳理一下這些問題的回答要點:
先簡單回顧Java中的數據類型;
然後詳細説明Java中的8種基本類型,每種類型的作用、取值範圍;
接着説一下各類型之間的轉換問題;
詳細説一下自動類型轉換和強制類型轉換。
這些面試題的重點答案,我已在內容中用紅色標明瞭,這些內容需要理解的東西並不多,主要是以記憶為主,各位好好記一下吧!