一道JAVA面試題引起的基礎回顧!
請記住一些約定:(這是很底層的東西,也是計算機的基礎知識,不要拿十萬個爲什麼來自問或反問?因爲回答這些問題就跟你問“1+1爲什麼等於2”一樣的讓人抓狂!)
計算機的語言:只有二進制,那永遠是0和1,沒有0和1的話,全世界的顯示器都將熄滅了!
再底層次說一點:
在模擬電路里,1代表開關的接通,0代表開關的斷開,這樣就形成原始的電信號。自然界有很多的自然參數(比如聲,光,磁,壓力,溼度,溫度,微波)我們故且叫它自然信號,可以通過相應的信號感測器將這些具有自然特性的信號轉換成模擬自然參數和狀態的電信號;也就是信息領域裏研究的模擬信號;
在數字電路里,0代表低電平,1代表高電平,如此就是一個脈衝,脈衝有上升沿(0—>1瞬間)和下降沿(1—>0瞬間),利用上升沿和下降沿我們可以做很多事情,比如用保持寄存器(RS)來保存其狀態。。。如此的一個個脈衝形成一種信號,也就是常說的數字信號,現在的計算機領域裏多研究的是數字信號。我們知道通過模/數(A/D)和數/模(D/A)可以實現着二信號之間的轉換。
計算機正是利用這樣的信號來發揮它的超能力,理解了0和1的本質就不會對二進制有什麼好奇了!
(不再作任何說明,下面所有的例子以JAVA爲例講解。)
Q1:爲什麼還會有八進制、十進制、十六進制?
其實進制是多少都無所謂,都是一種計數的方式和手段,只不過我們人類的世界裏已經習慣了十進制的計數方式,習慣用作慣例,慣例形成規則,竟而形成標準和規範,所以我們在編程中常用的還是10進制計數方式。
不過數據在計算機中最終以二進制的形式存在,所以有時候使用二進制,可以更直觀地解決問題。但二進制數真TM的太長了。比如JAVA中int 類型佔用4個字節*8=32位。INT類型100的二進制表示爲:
0000 0000 0000 0000 0110 0100
面對這麼長的數進行思考或操作,沒有人會愛上她。因此C/C++,JAVA 沒有提供在代碼裏直接寫二進制數的方法,但提供了直接寫8進制和16進制支持。
用16進制或8進制可以解決表達二進制的問題。因爲,進制越大,數的表達長度也就越短。不過,爲什麼偏偏是16或8進制,而不其它的諸如7或21進制呢?
2、8、16,分別是2的1次方,3次方,4次方。這一點使得三種進制之間可以非常方便地互相轉換。8進制或16進制縮短了二進制數長度,但卻保持了二進制數的表達特點。
Q2:怎樣區分二進制,八進制,十進制,十六進制?
JAVA中基本類型:
byte:8位,即1字節,表示範圍:-128——127
char:16位,即2字節,表示範圍:0——65535
short:16位,即2字節,表示範圍:-32768——32767
int:32位,即4字節,表示範圍:-(2的31次冪)——(2的31次冪)-1
float:32位
long:64位,即8字節,表示範圍:-(2的63次冪)——(2的63次冪)-1
double:64位
例如:
二進制(8位機):1000 0000 ——> 十進制:(-128)——>八進制:(0200,雖然0600也表示-128但是9位溢出)——>十六進制:(0x80);
二進制(16位機)1111 1111 1111 1111——>十進制:(-1)——>八進制:(0177777)——>十六進制:(0xFFFF);
二進制(32位機)1111 1111 1111 1111 1111 1111 1111 0001 ——>十進制:(-15)——>八進制:(0377 7777 7761)——>十六進制:(0xFFFF FFF1);
記住一個約定:二進制裏是用0和1來表示正負的,最高位爲符號位,最高位爲1代表負數,最高位爲0代表正數;
記住另外一個約定:
八進制:以“0”開頭;
十六進制:“0x”開頭;
十進制:我們最熟悉,不說了;
二進制:只有0和1的;
但1001100我們怎麼看,那要看具體的編程環境的變量或參數類型聲明是什麼,盲目說是二進制或十進制都是不對的;
EG1:一道典型的JAVA面試題?看看你做得出不O(∩_∩)O~
package org.test;
public class TestJava {
public static void main(String[] args) {
int i = 0xFFFFFFF1;
int j = ~i; // 按位取反運算
System.out.println(i);
System.out.println(j);
}
}
輸出結果:
-15
14
這是爲什麼呢?自己想去O(∩_∩)O~
Q3:八位二進制數爲什麼表示的範圍是: -128 —— +127?
計算機對有符號數(包括浮點數)的表示有三種方法:原碼、反碼和補碼
8位原碼能夠表示數的範圍是 -127~127
8位反碼能夠表示數的範圍是 -127~127
8位補碼能夠表示數的範圍是 -128~127
既然範圍是-128~127,那肯定是用補碼表示的。
計算機沒有你想象的那麼聰明,能夠自覺的對正數和負數進行區分和識別,所以我們人類就給他們制定了一系列規則:
我們把最高位規定爲符號位,1爲負,0爲正;
1000 0000——1111 1111表示-128到-1, 0000 0000——0111 1111表示0-127;
例如:
已知補碼1111 1111——>原碼1000 0001,反碼1111 1110;
負數補碼——>>原碼計算規則:
看到最高位爲1,一個負數,
把符號位去掉,剩下0111 1111,然後減1得到0111 1110,再取反得到原碼1000 0001;
負數補碼——>>反碼計算規則:
看到最高位爲1,一個負數,反碼=補碼-1,所以得到反碼 1111 1110;
若爲0表示正數,補碼=原碼=反碼,算都不用算的;
所以說補碼就是二進制裏表示負數的一種方法,對正數求原碼、反碼、補碼沒什麼意義;
正數的原碼反碼補碼是一樣的.
補碼的表示範圍爲:
(-128~0~127)共256個.
注意: (-128)沒有相對應的原碼和反碼。-128——>(1000 0000)
下面摘抄網上的一些講解,覺得蠻不錯的。
原碼:最高位爲符號位,“0”表示正,“1”表示負,其餘位表示數值的大小。
反碼:正數的反碼與其原碼相同;負數的反碼是對其原碼逐位取反,但符號位除外。
補碼:正數的補碼與其原碼相同;負數的補碼是在其反碼的末位加1。
1、原碼、反碼和補碼的表示方法
(1)原碼:在數值前直接加一符號位的表示法。
例如: 符號位 數值位
[+7]原= 0 0000111 B
[-7]原= 1 0000111 B
注意:a. 數0的原碼有兩種形式:
[+0]原=00000000B [-0]原=10000000B
b. 8位二進制原碼的表示範圍:-127~+127
(2)反碼:
正數:正數的反碼與原碼相同。
負數:負數的反碼,符號位爲“1”,數值部分按位取反。
例如: 符號位 數值位
[+7]反= 0 0000111 B
[-7]反= 1 1111000 B
注意:a. 數0的反碼也有兩種形式,即
[+0]反=00000000B
[- 0]反=11111111B
b. 8位二進制反碼的表示範圍:-127~+127
(3)補碼
2)補碼的表示:
正數:正數的補碼和原碼相同。
負數:負數的補碼則是符號位爲“1”,數值部分按位取反後再在末位(最低位)加1。也就是“反碼+1”。
例如: 符號位 數值位
[+7]補= 0 0000111 B
[-7]補= 1 1111001 B
補碼在微型機中是一種重要的編碼形式,請注意:
a.採用補碼後,可以方便地將減法運算轉化成加法運算,運算過程得到簡化。正數的補碼即是它所表示的數的真值,而負數的補碼的數值部份卻不是它所表示的數的真值。採用補碼進行運算,所得結果仍爲補碼。
b.與原碼、反碼不同,數值0的補碼只有一個,即 [0]補=00000000B。
c.若字長爲8位,則補碼所表示的範圍爲-128~+127;進行補碼運算時,應注意所得結果不應超過補碼所能表示數的範圍。
2.原碼、反碼和補碼之間的轉換
由於正數的原碼、補碼、反碼錶示方法均相同,不需轉換。
在此,僅以負數情況分析。
(1) 已知原碼,求補碼。
例:已知某數X的原碼爲10110100B,試求X的補碼和反碼。
解:由[X]原=10110100B知,X爲負數。求其反碼時,符號位不變,數值部分按位求反;求其補碼時,再在其反碼的末位加1。
1 0 1 1 0 1 0 0 原碼
1 1 0 0 1 0 1 1 反碼,符號位不變,數值位取反
1 +1
1 1 0 0 1 1 0 0 補碼
故:[X]補=11001100B,[X]反=11001011B。
(2) 已知補碼,求原碼。
分析:按照求負數補碼的逆過程,數值部分應是最低位減1,然後取反。但是對二進制數來說,先減1後取反和先取反後加1得到的結果是一樣的,故仍可採用取反加1 有方法。
例:已知某數X的補碼11101110B,試求其原碼。
解:由[X]補=11101110B知,X爲負數。求其原碼錶示時,符號位不變,數值部分按位求反,再在末位加1。
1 1 1 0 1 1 1 0 補碼
1 0 0 1 0 0 0 1 符號位不變,數值位取反
1 +1
1 0 0 1 0 0 1 0 原碼
1.3.2 有符號數運算時的溢出問題
請大家來做兩個題目:
1)(+72)+(+98)=?
0 1 0 0 1 0 0 0 B +72
+ 0 1 1 0 0 0 1 0 B +98
1 0 1 0 1 0 1 0 B -42
2)(-83)+(-80)=?
1 0 1 0 1 1 0 1 B -83
+ 1 0 1 1 0 0 0 0 B -80
0 1 0 1 1 1 0 1 B +93
思考:這兩個題目,按照正常的法則來運算,但結果顯然不正確,這是怎麼回事呢?
答案:這是因爲發生了溢出。