「MoreThanJava」Day2:變數、數據類型和運算符
- 2020 年 7 月 4 日
- 筆記
- MoreThanJava

- 「MoreThanJava」 宣揚的是 「學習,不止 CODE」,本系列 Java 基礎教程是自己在結合各方面的知識之後,對 Java 基礎的一個總回顧,旨在 「幫助新朋友快速高品質的學習」。
- 當然 不論新老朋友 我相信您都可以 從中獲益。如果覺得 「不錯」 的朋友,歡迎 「關注 + 留言 + 分享」,文末有完整的獲取鏈接,您的支援是我前進的最大的動力!
Part 1. 數據類型

假設您遇到了以下撕碎的紙片,您覺得會是什麼意思?

在不了解上下文的情況下,很難說出 MIX 的含義,它可能是羅馬數字 1009,也可以是英語單詞 mix 或者別的什麼東西。
在不知道上下文的情況下,一串字母沒有任何意義。
與一串字母一樣,一串 01 的含義取決於如何使用。而決定這一串數據如何使用的方案被稱為其 數據類型 (跟文件類型有些類似)。
8 種基本數據類型
Java 是一種強類型語言。這意味著必須為每一條數據聲明一種類型。在 Java 中共有 8 種基本類型 (primitive type),其中 4 種整型、2 種浮點類型、1 種字元類型、1 種表示真值的 boolean (布爾) 類型。
整型
整型被用來表示沒有小數部分的數值,允許是負數。Java 提供了 4 種整型,具體內容如下:
| 類型 | 存儲需求 | 取值範圍 |
|---|---|---|
| int | 4 位元組 | -2147483648 ~ 2147483647 (剛超過 20 億,這個數值也就是 232 對半分成正負值,32=4位元組*每個位元組8位) |
| short | 2 位元組 | -32768 ~ 32767 |
| long | 8 位元組 | -9223372036854775808 ~ 9223372036854775807 |
| byte | 1 位元組 | -128 ~ 127 |
在通常情況下,int 類型最常用。但如果想要表示整個地球的居住人口,那麼就需要使用 long 類型了。byte 和 short 類型主要用於特定的應用場合,例如,底層的文件處理或者存儲空間很寶貴時的大數組 (因為節約記憶體)。
浮點類型
浮點類型用於表示有小數部分的數值。在 Java 中有兩種浮點類型,具體內容如下:
| 類型 | 存儲需求 | 取值範圍 |
|---|---|---|
| float | 4 位元組 | 大約 ±3.40282347E + 38F (大約有效數為 6 ~ 7) |
| double | 8 位元組 | 大約 ±1.7976931486231580E + 308 (大約有效數為 15 位) |
double 表示這種類型的數值精度是 float 類型的兩倍 (也有人稱 double 為雙精度數值)。
浮點數精度問題
問一個問題:0.1 + 0.2 = ?

先別奇怪,在 IDEA 中嘗試著輸出一下這句話就知道了:
System.out.println(0.1 + 0.2);
// 輸出:0.30000000000000004
0.1 + 0.2 為什麼會等於 0.30000000000000004?而不是我們想像中的 0.3?
這不是因為它們在計算時出現了錯誤,而是因為浮點數計算標準的要求。
首先我們要明確一點:編程中的浮點數並不能和數學中的小數看做同一個東西。
- 編程中的浮點數的精度往往都是有限的,單精度的浮點數使用
32位表示,而雙精度的浮點數使用64位表示; - 數學中的小數系統可以通過引入無限序列....可以表示任意的實數;
請考慮使用 十進位 表示 1/3:
0.3333333333333333....
如果想要完整地表達 1/3 的精度,那麼小數點之後的 3 需要無限地寫下去。如果需要讓你在一張紙上表達清晰,顯然由於紙張大小的限制你無法無限地寫下去...
0.1 和 0.2 在 二進位 中同 1/3 在 十進位 中一樣,不屬於整數的範疇,所以只能用近似值來代替,由於精度的限制 0.1 和 0.2 使用單精度浮點數表示的實際值為:0.100000001490116119384765625 和 0.20000000298023223876953125,把它們相加起來得到的結果與我們在一開始看到的非常相似:

在交易系統或者科學計算的場景中,如果需要更高的精度小數,可以使用具有 28 個有效位數的 decimal 或者直接使用分數,不過這些表示方法的開銷也隨著有效位數的增加而提高,我們應該按照需要選擇最合適的方法。
重新回到最開始的問題 — 0.1 和 0.2 相加不等於 0.3 的原因包括以下兩個:
- 使用二進位表達十進位的小數時,某些數字無法被有限位的二進位小數表示;
- 單精度和雙精度的浮點數只包括
7位或者15位的有效小數位,存儲需要無限位表示的小數時只能存儲近似值;
在使用單精度和雙精度浮點數時也應該牢記它們只有 7 位和 15 位的有效位數。
char 類型
char 用來表示單個字元。在 Java 中 char 類型的數據使用 16 位來存儲和表示,而許多程式語言則僅用 8 位。
char 類型的字面量值需要用 單引號 括起來。例如:'A' 是編碼值為 65 的 字元常量,它與 "A" 不同,"A" 是僅包含字元 A 的 字元串 (String 類型)。
強烈建議:不要在程式中使用 char 類型,除非您確實需要處理 UTF-16 程式碼單元。
(更多相關資料放入了下面的自取資料,感興趣可以去閱讀一下更多 char 類型的東西,不感興趣跳過即可...)
boolean 類型
boolean (布爾) 類型有兩個值:false 和 true (注意這兩個是布爾類型的字面常量也是保留字),用來判斷邏輯條件是否成立。
對象類型
Java 中的所有數據都屬於「基本數據類型」或「對象」中的一種。
雖然只有八種基本數據類型,但 Java 有許多滿足您需求的相關類型的對象供您使用,例如,表示字元串的 String 類型。
我們會在之後的內容中更多地討論對象 (因為 Java 是一種面向對象的程式語言),現在,您需要了解以下資訊:
- 基本數據類型使用少量的固定位元組數 (下面會詳細介紹);
- 只有
8種基本數據類型,您無法創建新的原始數據類型; - 一個對象是一個較大的數據塊,可能使用很多位元組的記憶體;
- 對象類型的數據被稱為 類;
- Java 中已經封裝了足夠多的類用來滿足您各類的需求,您也可以發明新的類來滿足程式的特定需求;
Part 2. 變數

電腦記憶體中有數以十億計的位元組用於存儲機器指令和數據。
程式運行時,某些記憶體用於存儲機器指令,而另外一些則用於存儲數據。後來,當另一個程式運行時,以前保存的機器指令中的某些位元組現在可以用來保存數據,而之前保存的數據中的某些位元組現在可以保存機器指令。
電腦先驅 約翰·馮·諾依曼 (John von Neumann) 的想法是:使用相同的存儲器來存儲指令和數據。
回想一下,數據類型是一種使用位模式來表示值的方案。

可以把 變數 視為一個由一個或多個位元組組成的小盒子,該盒子可以使用特定的數據類型保存值。
要將值存儲在記憶體中,以後再取回它,則程式必須為每個變數指定一個名稱,如 className/ payAmount (變數名採用小駝峰命名法)。
變數隨運行程式的需要而變化。當正在運行的程式不再需要變數時,該記憶體部分可用於其他目的。
聲明變數
在 Java 中,每個變數都必須有一個類型 (type)。在聲明變數時,需要先指定變數的類型,然後是變數名:
double salary;
int vacationDays;
long earthPopluation;
boolean finished;
可以看到,每個變數都以分號 (;) 結束。由於聲明是一條完整的 Java 語句,而所有的 Java 語句都以分號結束,所以這裡的分號是必須的。
變數命名
在 Java 中,變數命名需要遵循以下硬性規定和強烈建議遵守的非硬性規定:
硬性規則
- 變數名必須是一個以字母開頭並由字母或數字構成的序列 (儘管
$是合法的,但不要在你自己的程式碼中使用這個字元,它只用在 Java 編譯器或其他工具生成的名字中); - 每一個字元都有意義,且大小寫敏感;
- 不要使用 Java 中的保留字;
《阿里巴巴 Java 開發手冊》規則
- 【強制】 程式碼中的命名 (所有標識符) 均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束;(反例:
$name) - 【強制] 程式碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式;(反例:
DaZhePromotion- 打折) - 【強制】 杜絕完全不規範的縮寫,避免詞不達意;(反例:
condition縮寫成condi) - 【推薦】 為了達到程式碼自解釋的目的,任何自定義編程元素在命名時,使用盡量完整的單片語合來表達其意;(反例:
int a;的隨意命名方式)
變數初始化
聲明一個變數之後,必須用賦值語句對變數進行顯式初始化,千萬不要使用未初始化的變數的值。例如,Java 編譯器認為下面的語句序列是錯誤的:
int amount;
System.out.println(amount); // ERROR -- variable not initialized
要相對一個已經聲明過的變數進行賦值,就需要將變數名放在等號 (=) 左側,再把一個適當取值放在等號的右側:
int amount;
amount = 12;
也可以將變數的聲明和初始化放在同一行中。例如:
int amount = 12;
最後,在 Java 中可以將聲明放在程式碼中的任何地方。
但讓變數儘可能地靠近變數第一次使用的地方,這是一種良好的程式編寫風格。
變數使用範例
我們來使用變數完成兩個數的加減乘除:
int num1 = 2;
int num2 = 3;
System.out.println(num1 + num2);
System.out.println(num1 - num2);
System.out.println(num1 * num2);
System.out.println(num1 / num2);
Part 3. 運算符

電腦的最基本用途之一就是執行數學運算,作為一門電腦語言,Java 也提供了一套豐富的運算符來操縱變數。我們可以把運算符分成以下幾組:
- 算術運算符;
- 關係運算符;
- 位運算符;
- 邏輯運算符;
- 賦值運算符;
- 其他運算符;
算術運算符
算術運算符用在數學表達式中,它們的作用和在數學中的作用一樣。下表列出了所有的算術運算符。
表格中的實例假設整數變數 A 的值為 10,變數 B 的值為 20:

實例
下面的簡單示常式序演示了算術運算符。複製並粘貼下面的 Java 程式並保存為 Test.java 文件,然後編譯並運行這個程式:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 25;
int d = 25;
System.out.println("a + b = " + (a + b));
System.out.println("a - b = " + (a - b));
System.out.println("a * b = " + (a * b));
System.out.println("b / a = " + (b / a));
System.out.println("b % a = " + (b % a));
System.out.println("c % a = " + (c % a));
System.out.println("a++ = " + (a++));
System.out.println("a-- = " + (a--));
// 查看 d++ 與 ++d 的不同
System.out.println("d++ = " + (d++));
System.out.println("++d = " + (++d));
}
}
運行結果:
a + b = 30
a - b = -10
a * b = 200
b / a = 2
b % a = 0
c % a = 5
a++ = 10
a-- = 11
d++ = 25
++d = 27
i++ 與 ++i 到底有什麼不同?
實際上,不管是前置 ++,還是後置 ++,都是先將變數的值加 1,然後才繼續計算的。
二者之間真正的區別是:前置 ++ 是將變數的值加 1 後,使用增值後的變數進行運算的,而後置 ++ 是首先將變數賦值給一個臨時變數,接下來對變數的值加 1,然後使用那個臨時變數進行運算。

關係運算符
下表為Java支援的關係運算符。
表格中的實例整數變數 A 的值為 10,變數 B 的值為 20:

實例
下面的簡單示常式序演示了關係運算符。複製並粘貼下面的 Java 程式並保存為 Test.java 文件,然後編譯並運行這個程式:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("a == b = " + (a == b));
System.out.println("a != b = " + (a != b));
System.out.println("a > b = " + (a > b));
System.out.println("a < b = " + (a < b));
System.out.println("b >= a = " + (b >= a));
System.out.println("b <= a = " + (b <= a));
}
}
運行結果:
a == b = false
a != b = true
a > b = false
a < b = true
b >= a = true
b <= a = false
位運算符
Java定義了位運算符,應用於整數類型 (int),長整型 (long),短整型 (short),字元型 (char),和位元組型 (byte) 等類型。
位運算符作用在所有的位上,並且按位運算。假設 a = 60,b = 13; 它們的二進位格式表示將如下:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A = 1100 0011
下表列出了位運算符的基本運算,假設整數變數 A 的值為 60 和變數 B 的值為 13:

實例
下面的簡單示常式序演示了關係運算符。複製並粘貼下面的 Java 程式並保存為 Test.java 文件,然後編譯並運行這個程式:
public class Test {
public static void main(String[] args) {
int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b; /* 12 = 0000 1100 */
System.out.println("a & b = " + c);
c = a | b; /* 61 = 0011 1101 */
System.out.println("a | b = " + c);
c = a ^ b; /* 49 = 0011 0001 */
System.out.println("a ^ b = " + c);
c = ~a; /*-61 = 1100 0011 */
System.out.println("~a = " + c);
c = a << 2; /* 240 = 1111 0000 */
System.out.println("a << 2 = " + c);
c = a >> 2; /* 15 = 1111 */
System.out.println("a >> 2 = " + c);
c = a >>> 2; /* 15 = 0000 1111 */
System.out.println("a >>> 2 = " + c);
}
}
運行結果:
a & b = 12
a | b = 61
a ^ b = 49
~a = -61
a << 2 = 240
a >> 2 = 15
a >>> 2 = 15
邏輯運算符
下表列出了邏輯運算符的基本運算,假設布爾變數 A 為真,變數 B 為假:

實例
下面的簡單示常式序演示了關係運算符。複製並粘貼下面的 Java 程式並保存為 Test.java 文件,然後編譯並運行這個程式:
public class Test {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
System.out.println("a && b = " + (a && b));
System.out.println("a || b = " + (a || b));
System.out.println("!(a && b) = " + !(a && b));
}
}
運行結果:
a && b = false
a || b = true
!(a && b) = true
短路邏輯運算符
當使用與邏輯運算符時,在兩個操作數都為 true 時,結果才為 true,但是當得到第一個操作為 false 時,其結果就必定是 false,這時候就不會再判斷第二個操作了。
事實上,如果所有的邏輯表達式都有一部分不必計算,那將獲得潛在的性能提升。
實例:
public class LuoJi {
public static void main(String[] args) {
int a = 5;//定義一個變數;
boolean b = (a < 4) && (a++ < 10);
System.out.println("使用短路邏輯運算符的結果為" + b);
System.out.println("a的結果為" + a);
}
}
運行結果:
使用短路邏輯運算符的結果為false
a的結果為5
賦值運算符
下面是 Java 語言支援的賦值運算符:

實例
下面的簡單示常式序演示了關係運算符。複製並粘貼下面的 Java 程式並保存為 Test.java 文件,然後編譯並運行這個程式:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int c = 0;
c = a + b;
System.out.println("c = a + b = " + c);
c += a;
System.out.println("c += a = " + c);
c -= a;
System.out.println("c -= a = " + c);
c *= a;
System.out.println("c *= a = " + c);
a = 10;
c = 15;
c /= a;
System.out.println("c /= a = " + c);
a = 10;
c = 15;
c %= a;
System.out.println("c %= a = " + c);
c <<= 2;
System.out.println("c <<= 2 = " + c);
c >>= 2;
System.out.println("c >>= 2 = " + c);
c >>= 2;
System.out.println("c >>= 2 = " + c);
c &= a;
System.out.println("c &= a = " + c);
c ^= a;
System.out.println("c ^= a = " + c);
c |= a;
System.out.println("c |= a = " + c);
}
}
運行結果:
c = a + b = 30
c += a = 40
c -= a = 30
c *= a = 300
c /= a = 1
c %= a = 5
c <<= 2 = 20
c >>= 2 = 5
c >>= 2 = 1
c &= a = 0
c ^= a = 10
c |= a = 10
其他運算符
條件運算符 (?😃
條件運算符也被稱為三元運算符。該運算符有 3 個操作數,並且需要判斷布爾表達式的值。該運算符的主要是決定哪個值應該賦值給變數。
variable x = (expression) ? value if true : value if false
實例
下面的簡單示常式序演示了關係運算符。複製並粘貼下面的 Java 程式並保存為 Test.java 文件,然後編譯並運行這個程式:
public class Test {
public static void main(String[] args) {
int a, b;
a = 10;
// 如果 a 等於 1 成立,則設置 b 為 20,否則為 30
b = (a == 1) ? 20 : 30;
System.out.println("Value of b is : " + b);
// 如果 a 等於 10 成立,則設置 b 為 20,否則為 30
b = (a == 10) ? 20 : 30;
System.out.println("Value of b is : " + b);
}
}
運行結果:
Value of b is : 30
Value of b is : 20
instanceof 運算符
該運算符用於操作對象實例,檢查該對象是否是一個特定類型(類類型或介面類型)。
instanceof 運算符使用格式如下:
( Object reference variable ) instanceof (class/interface type)
如果運算符左側變數所指的對象,是操作符右側類或介面 (class/interface) 的一個對象,那麼結果為真。
下面是一個例子:
String name = "James";
boolean result = name instanceof String; // 由於 name 是 String 類型,所以返回真
要點回顧
- Java 是一種強類型語言,任何一種數據都屬於
1種基本類型或者對象類型 (類) 中的一種; 8種基本數據類型;- 為什麼引入變數、如何定義使用變數以及變數名的命名規範;
- Java 中的運算符以及使用實例;
練習
獲取用戶輸入 Scanner
java.util.Scanner 是 Java5 的新特徵,我們可以通過 Scanner 類來獲取用戶的輸入。
下面是創建 Scanner 對象的基本語法:
Scanner scanner = new Scanner(System.in);
在下面的示例中,我們將使用該類的 nextLine() 方法,該方法用於讀取字元串:
import java.util.Scanner; // Import the Scanner class
class MyClass {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // Create a Scanner object
System.out.println("Enter username");
String userName = scanner.nextLine(); // Read user input
System.out.println("Username is: " + userName); // Output user input
}
}
輸入類型
在上面的示例中,我們使用了 nextLine() 用於讀取字元串的方法。要閱讀其他類型,請查看下錶:

練習 1:輸入圓的半徑計算周長和面積
參考答案:
import java.util.Scanner;
public class Tester {
public static void main(String[] args) {
System.out.println("請輸入圓的半徑:");
Scanner scanner = new Scanner(System.in);
int radius = scanner.nextInt();
// 計算周長和面積
double area = radius * radius * 3.14;
double perimeter = 2 * 3.14 * radius;
System.out.println("該圓的面積為:" + area);
System.out.println("該圓的周長為:" + perimeter);
}
}
練習 2:輸入年份判斷是不是閏年
提示:
閏年需要滿足:
- 能被
4整除,並且不能被100整除; - 或者能被
400整除;
參考答案:
import java.util.Scanner;
public class Tester {
public static void main(String[] args) {
System.out.println("請輸入年份:");
Scanner scanner = new Scanner(System.in);
int year = scanner.nextInt();
boolean leapYear;
boolean divisbleBy4 = year % 4 == 0;
boolean notDivisbleBy100 = year % 100 != 0;
boolean divisibleBy400 = year % 400 == 0;
leapYear = (divisbleBy4 && notDivisbleBy100) || divisibleBy400;
System.out.println("該年份是否是閏年:" + leapYear);
}
}
自取資料
擴展閱讀推薦
- Java 基本數據類型 | 菜鳥教程 - //www.runoob.com/java/java-basic-datatypes.html
- 浮點類型精度深度討論:
- 為什麼 0.1 + 0.2 = 0.3? - //draveness.me/whys-the-design-decimal-and-rational/
- 為什麼 0.1 + 0.2 = 0.300000004? - //draveness.me/whys-the-design-floating-point-arithmetic/#fn:2
- IEEE754標準: 浮點數在記憶體中的存儲方式 - //www.jianshu.com/p/8ee02e9bb57d
- 為什麼Java中char類型不能完整表示一個字元? - //fookwood.com/java-string-charset-char
推薦書籍
Java 核心技術·卷 I(原書第 11 版)

推薦理由: 這本書在知識體系完整充實的同時,又比《Thinking in Java》暴風式的知識洗禮來得輕鬆,新人入門書籍強烈推薦!
碼出高效:Java開發手冊

推薦理由: 阿里系出品。從最基礎的電腦基礎入手,到 Java 的方方面面,加上精美的配圖和通俗易懂的解釋,是非常適合新手閱讀的一本兒關於 Java 的技術書籍。
參考資料
- Introduction to Computer Science using Java - //programmedlessons.org/Java9/index.html#part02
- Java 運算符 | 菜鳥教程 - //www.runoob.com/java/java-operators.html
- 《Java 核心技術 卷I》(第11版)
- 本文已收錄至我的 Github 程式設計師成長系列 【More Than Java】,學習,不止 Code,歡迎 star://github.com/wmyskxz/MoreThanJava
- 個人公眾號 :wmyskxz,個人獨立域名部落格:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長!

非常感謝各位人才能 看到這裡,如果覺得本篇文章寫得不錯,覺得 「我沒有三顆心臟」有點東西 的話,求點贊,求關注,求分享,求留言!
創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文章見!

