對於初級或部分中級Java程式設計師來說,關於Java資料型別的面試題是屬於比較高頻的一個考點,關於資料型別的面試題及筆試題還是比較多的。
一. Java資料型別1. 概述Java語言是靜態型別的(statical typed),也就是說所有變數和表示式的型別在編譯時就已經完全確定了。由於是statical typed,也就導致了Java語言是強型別(Strong typed)的。強型別則意味著每個變數都屬於某一種型別,每個表示式也都屬於某一種型別,並且每種型別都是嚴格定義的。
而資料型別則限制了該變數可以儲存哪些值,表示式最終產生什麼值,同時限制了這些值可以進行的操作型別以及操作的具體方式。所有的賦值操作,無論是顯式的還是在方法呼叫中透過引數傳遞的,都要進行型別的相容性檢查。
2. Java資料型別Java的資料型別總體上分為兩大類,基本型別和引用型別!
2.1 基本型別(primitive type)
基本型別包括數值型別(numeric types)和布林型別(boolean)。數值型別又分為整型(integer types)和浮點型(floating-point type),其中整型有5種:byte、short、int、long、char(char本質上是一種特殊的int);而浮點型別則包括float和double。
布林型別的值只有2個,也就是true和false。
所有的基本型別都直接包含值(directly contain value)。
2.2 引用型別(reference type)
Java有 6種 引用型別(物件型別):類、介面、陣列、列舉、註解和null物件。
其中null是一種特殊的type,但是你不能宣告一個變數為null的型別,null type的唯一取值就是null。null可以賦值給任意的引用型別或者轉化成任意的引用型別。在實踐中,一般把null當做字面值(literal),這個字面值可是是任意的引用型別。
3. 基本型別取值範圍4. 引用型別間轉換規則
子類能直接轉換為父類 或 介面型別;父類轉換為子類要強制型別轉換;且在執行時若實際不是對應的物件,會丟擲ClassCastException執行時異常;二. Java型別轉換在Java中將一種型別的值賦給另一種型別是很常見的,其中boolean型別與所有其他7種類型都不能進行轉換,這一點很明確。對於其他7中數值型別,它們之間都可以進行轉換,但是可能會存在精度損失或者其他一些變化
1. 型別轉換方式1.1 自動轉換(隱式轉換)
自動轉換時發生擴寬(widening conversion),因為較大的型別(如int)要儲存較小的型別(如byte),記憶體總是足夠的,不需要強制轉換。無需任何操作。
自動型別轉換特點: (1).兩種型別是彼此相容的;(2).轉換後的目標型別佔的空間範圍一定要大於被轉化的源型別; (3).由低位元組向高位元組自動轉換(圖中黑線表示無資料丟失的自動資料轉換,紅線表示轉換中可能發生精度丟失)。
1.2 強制轉換(顯式轉換):需要顯式轉換,也就是需要使用轉換運算子。
如果要把大的轉成小的,或者在short與char之間進行轉換,就必須強制轉換,也被稱作縮小轉換(narrowing conversion),因為必須顯式地使數值更小以適應目標型別。強制轉換採用轉換運算子()。嚴格地說,將byte轉為char不屬於narrowing conversion),因為從byte到char的過程其實是byte-->int-->char,所以widening和narrowing都有。強制轉換除了可能的精度損失外,還可能使模(overall magnitude)發生變化。
將容納更多資訊的資料型別轉換成一個容量更小的資料型別,可能存在精度損失的風險,編譯器要求程式設計師進行強制型別轉換。而在強制轉換過程中可能會發生資料溢位,必須警惕。例如 int a=(int)3.14;
1.3 7種類型按範圍排序
byte <(short=char)< int < long < float < double
如果從小轉換到大,可以自動完成型別轉換,而從大到小,必須強制轉換。short和char兩種相同型別也必須強制轉換。
7中基本型別轉換總結如下圖:
三. 型別轉換面試題short s = 1; s = s + 1;有沒有問題?如果有怎麼解決?short s = 1; s += 1;有沒有問題?如果有怎麼解決?1) 對於short s1=1;s1=s1+1來說,在s1+1運算時會自動提升表示式的型別為int,那麼將int賦予給short型別的變數s1會出現型別轉換錯誤。 2) 對於short s1=1;s1+=1來說 +=是java語言規定的運算子,java編譯器會對它進行特殊處理,因此可以正確編譯。
2. char型別變數能不能儲存一箇中文的漢字,為什麼?
char型別變數是用來儲存Unicode編碼的字元的,unicode字符集包含了漢字,所以char型別當然可以儲存漢字的,還有一種特殊情況就是某個生僻字沒有包含在unicode編碼字符集中,那麼就char型別就不能儲存該生僻字。
3. Integer和int的區別
int是java的8種內建的原始資料型別。Java為每個原始型別都提供了一個封裝類,Integer就是int的封裝類,int變數的預設值為0,Integer變數的預設值為null。
Integer類內提供了一些關於整數操作的一些方法,例如上文用到的表示整數的最大值和最小值。
4. switch語句能否作用在byte上,能否作用在long上,能否作用在string上?
byte的儲存範圍小於int,可以向int型別進行隱式轉換,所以switch可以作用在byte上;
long的儲存範圍大於int,不能向int進行隱式轉換,只能強制轉換,所以switch不可以作用在long上;
switch()變數型別只能是int、short、char、byte和enum型別;
case後面只能是常量,可以是運算表示式,但一定要符合正確的型別。不能是變數,即便變數在之前進行了賦值,JVM依然會報錯。
string在1.7版本之前不可以,1.7版本之後switch就可以作用在string上了。
5. float f1 = (float)11.11; float f2 = 11.11f; 這兩種定義資料有什麼不同嗎?
f1其實是透過一個double型別轉換過來的。而f2本身就是一個float型別。
6. byte b1=3, b2=4 , b ; b=b1+b2 ; b=3+4 ; 哪句是編譯失敗的呢?為什麼呢?
b = b1 + b2;會編譯失敗
因為當是變數相加時,會首先看型別,最終把結果賦值的也會考慮型別問題。
常量相加,首先是先做加法,然後看結果是否在賦值的資料類型範圍內,如果不是,才會報錯。
透過反編譯工具也會發現上面的程式碼、會直接被編譯為(.class)
byte b1 = 3 , b2 = 4 , b ;
b = 7 ;
7. byte b = 130;有沒有問題?如果我想讓賦值正確,可以怎麼做?結果是多少呢?
我們要想知道結果是什麼,就應該知道是如何進行計算的。而我們又知道計算機中資料的運算都是補碼進行的,顯示給我們的是原碼轉換為十進位制的數字。那我們要得到補碼,首先要計算出資料的二進位制。
獲取130這個資料的二進位制。00000000 00000000 00000000 10000010這是130的原碼,也是反碼,還是補碼。做擷取操作,截成byte型別的了。10000010這個結果是補碼。已知補碼求原碼。byte b= (byte)130;//強制轉換System.out.pringln(b);//-126
對應我們看見的十進位制就是-126