基本數據類型:Java世界的基礎積木
當我們用Java編寫程序時,首先要學會如何表示現實世界中的數據。就像我們用不同容器裝水、裝米、裝汽油一樣,Java為不同類型的數據設計了不同的"容器"——這就是數據類型。今天我們從最基礎的8種基本數據類型開始學起,它們是Java編程的"原子積木"。
整數類型:沒有小數點的數字
整數類型用於存儲不帶小數點的數字,Java提供了4種整數類型,它們的區別主要在於內存佔用大小和表示範圍:
表格
|
類型 |
內存佔用 |
表示範圍 |
應用場景 |
|
byte |
1字節 |
-128 ~ 127 |
節省內存的小整數,如文件流、網絡數據傳輸 |
|
short |
2字節 |
-32768 ~ 32767 |
較少使用,主要用於兼容性場景 |
|
int |
4字節 |
-2^31 ~ 2^31-1 |
默認整數類型,如年齡、數量等常規整數 |
|
long |
8字節 |
-2^63 ~ 2^63-1 |
大整數,如時間戳、身份證號等 |
💡 內存佔用小知識:1字節=8位二進制數,所以byte類型能表示2^8=256個數字(從-128到127)。記住int是默認類型,當需要表示超過int範圍的整數時,要在數字後加L(如10000000000L)。
下面是整數類型的代碼示例,我們可以在昨天搭建的VS Code環境中創建一個DataTypeDemo.java文件來測試:
public class DataTypeDemo {
public static void main(String[] args) {
// 整數類型示例
byte age = 25; // 年齡用byte足夠,因為人年齡很少超過127歲
short temperature = -15; // 温度用short,能表示-32768到32767的範圍
int population = 1400000000; // 中國人口用int剛好
long distance = 9460730472580800L; // 一光年的距離,必須加L表示long類型
// 輸出各變量值
System.out.println("年齡:" + age);
System.out.println("温度:" + temperature + "℃");
System.out.println("人口:" + population);
System.out.println("一光年距離:" + distance + "米");
}
}
浮點類型:帶小數點的數字
當需要表示帶小數點的數字(如身高1.75米、體重62.5公斤)時,就需要用到浮點類型。Java提供兩種浮點類型:
表格
|
類型 |
內存佔用 |
精度 |
應用場景 |
|
float |
4字節 |
約6-7位小數 |
內存緊張的場景,如遊戲圖形數據 |
|
double |
8字節 |
約15-17位小數 |
默認浮點類型,如科學計算、金融數據 |
⚠️ 注意:float類型的數字後必須加F(如3.14F),否則會被當作double處理。double是默認浮點類型,大多數情況下推薦使用double,因為它精度更高。
浮點類型代碼示例:
public class FloatDemo {
public static void main(String[] args) {
float piFloat = 3.1415926F; // 注意加F
double piDouble = 3.141592653589793; // 默認double類型
System.out.println("float類型圓周率:" + piFloat); // 輸出約3.1415925
System.out.println("double類型圓周率:" + piDouble); // 輸出更精確的3.141592653589793
// 浮點運算注意事項:可能存在精度問題
double result = 0.1 + 0.2;
System.out.println("0.1 + 0.2 = " + result); // 輸出0.30000000000000004而非0.3
}
}
💡 為什麼0.1+0.2不等於0.3? 因為計算機用二進制存儲小數,有些十進制小數(如0.1)無法精確表示,會產生微小誤差。金融計算時應使用BigDecimal類避免此問題,這會在後續課程講到。
字符類型:單個文字符號
char類型用於存儲單個字符,佔用2字節,採用Unicode編碼,能表示包括中文在內的全球文字:
public class CharDemo {
public static void main(String[] args) {
char letter = 'A'; // 英文字母
char chinese = '中'; // 中文字符
char emoji = '\uD83D\uDE0A'; // 笑臉emoji的Unicode編碼
System.out.println("字母:" + letter); // 輸出A
System.out.println("中文:" + chinese); // 輸出中
System.out.println("表情:" + emoji); // 輸出😊
}
}
💡 Unicode小知識:每個字符都有唯一的Unicode編碼,如'A'是65,'中'是20013。可以用(int)chinese查看字符的Unicode值。
布爾類型:真或假
boolean類型只有兩個值:true(真)和false(假),主要用於條件判斷,佔用1字節:
public class BooleanDemo {
public static void main(String[] args) {
boolean isJavaFun = true;
boolean isFishFly = false;
System.out.println("Java有趣嗎?" + isJavaFun); // 輸出true
System.out.println("魚會飛嗎?" + isFishFly); // 輸出false
// 布爾值常用於條件判斷
if (isJavaFun) {
System.out.println("繼續學習Java吧!"); // 因為isJavaFun是true,所以會執行
}
}
}
變量與常量:數據的容器與固定值
變量:可以改變的量
變量就像一個貼了標籤的盒子,我們可以把數據放進去,也可以隨時更換盒子裏的數據。定義變量的語法是:數據類型 變量名 = 初始值;
public class VariableDemo {
public static void main(String[] args) {
// 聲明變量並初始化
int score = 85;
String name = "小明"; // String是引用類型,後面課程會講
System.out.println(name + "的成績是:" + score); // 輸出:小明的成績是:85
// 修改變量值
score = 92;
System.out.println("修改後的成績:" + score); // 輸出:修改後的成績:92
// 先聲明後初始化
double height; // 聲明變量
height = 1.75; // 初始化變量
System.out.println("身高:" + height + "米"); // 輸出:身高:1.75米
}
}
📝 變量命名規則:
- 只能包含字母、數字、下劃線(_)和美元符號($)
- 不能以數字開頭
- 不能使用Java關鍵字(如int、class、if等)
- 區分大小寫(score和Score是兩個不同變量)
- 建議使用駝峯命名法:如studentName、userAge
常量:固定不變的值
常量是程序運行過程中不能改變的值,用final關鍵字聲明:final 數據類型 常量名 = 值;
public class ConstantDemo {
public static void main(String[] args) {
// 聲明常量,常量名通常全大寫,多個單詞用下劃線連接
final double PI = 3.1415926535;
final int MAX_SCORE = 100;
System.out.println("圓周率:" + PI);
System.out.println("滿分:" + MAX_SCORE);
// 嘗試修改常量會編譯錯誤
// PI = 3.14; // 此行代碼會報錯:無法為最終變量PI分配值
}
}
💡 什麼時候用常量? 當某個值在程序中多次使用且不會改變時(如圓周率、税率、配置參數),應該定義為常量。這樣不僅提高可讀性,還方便維護(修改一處即可)。
運算符:數據的加工工具
運算符用於對數據進行運算處理,Java提供了豐富的運算符,我們可以按功能分為以下幾類:
算術運算符
用於基本的數學運算:
表格
|
運算符 |
作用 |
示例 |
結果 |
|
+ |
加法 |
5 + 3 |
8 |
|
- |
減法 |
5 - 3 |
2 |
|
* |
乘法 |
5 * 3 |
15 |
|
/ |
除法 |
5 / 3 |
1(整數相除取整) |
|
% |
取餘(模運算) |
5 % 3 |
2 |
|
++ |
自增 |
int a=5; a++ |
a變為6 |
|
-- |
自減 |
int b=5; b-- |
b變為4 |
代碼示例:
public class ArithmeticDemo {
public static void main(String[] args) {
int a = 10;
int b = 3;
System.out.println("a + b = " + (a + b)); // 13
System.out.println("a - b = " + (a - b)); // 7
System.out.println("a * b = " + (a * b)); // 30
System.out.println("a / b = " + (a / b)); // 3(整數相除)
System.out.println("a % b = " + (a % b)); // 1(10除以3餘1)
// 自增自減運算符
int c = 5;
c++; // 等價於 c = c + 1
System.out.println("c++ = " + c); // 6
int d = 5;
++d; // 等價於 d = d + 1
System.out.println("++d = " + d); // 6
// 前置++和後置++的區別
int e = 5;
int f = e++; // 先賦值再自增:f=5, e=6
System.out.println("e++賦值給f後:e=" + e + ", f=" + f);
int g = 5;
int h = ++g; // 先自增再賦值:g=6, h=6
System.out.println("++g賦值給h後:g=" + g + ", h=" + h);
}
}
賦值運算符
用於給變量賦值,最基本的是=,還有複合賦值運算符:
表格
|
運算符 |
等價於 |
示例 |
等價於 |
|
= |
- |
a = 5 |
a = 5 |
|
+= |
加後賦值 |
a += 3 |
a = a + 3 |
|
-= |
減後賦值 |
a -= 3 |
a = a - 3 |
|
*= |
乘後賦值 |
a *= 3 |
a = a * 3 |
|
/= |
除後賦值 |
a /= 3 |
a = a / 3 |
|
%= |
取餘後賦值 |
a %= 3 |
a = a % 3 |
代碼示例:
public class AssignmentDemo {
public static void main(String[] args) {
int a = 10;
a += 5; // a = a + 5 → 15
System.out.println("a += 5: " + a);
a -= 3; // a = a - 3 → 12
System.out.println("a -= 3: " + a);
a *= 2; // a = a * 2 → 24
System.out.println("a *= 2: " + a);
a /= 4; // a = a / 4 → 6
System.out.println("a /= 4: " + a);
a %= 5; // a = a % 5 → 1
System.out.println("a %= 5: " + a);
}
}
比較運算符
用於比較兩個值,返回boolean類型結果(true或false):
表格
|
運算符 |
作用 |
示例 |
結果 |
|
== |
等於 |
5 == 3 |
false |
|
!= |
不等於 |
5 != 3 |
true |
|
> |
大於 |
5 > 3 |
true |
|
< |
小於 |
5 < 3 |
false |
|
>= |
大於等於 |
5 >= 5 |
true |
|
<= |
小於等於 |
3 <= 1 |
false |
代碼示例:
public class ComparisonDemo {
public static void main(String[] args) {
int x = 5;
int y = 8;
System.out.println("x == y: " + (x == y)); // false
System.out.println("x != y: " + (x != y)); // true
System.out.println("x > y: " + (x > y)); // false
System.out.println("x < y: " + (x < y)); // true
System.out.println("x >= 5: " + (x >= 5)); // true
System.out.println("y <= 7: " + (y <= 7)); // false
// 比較字符串內容要用equals()方法,不能直接用==
String str1 = "hello";
String str2 = new String("hello");
System.out.println("str1 == str2: " + (str1 == str2)); // false(比較地址)
System.out.println("str1.equals(str2): " + str1.equals(str2)); // true(比較內容)
}
}
⚠️ 注意:==對於基本類型比較的是值,對於引用類型(如String)比較的是內存地址。比較字符串內容應該使用equals()方法。
邏輯運算符
用於連接多個條件,進行邏輯判斷:
表格
|
運算符 |
作用 |
特點 |
示例 |
結果 |
|
&& |
邏輯與 |
兩邊都為true才返回true,短路特性 |
true && false |
false |
|
|| |
邏輯或 |
至少一邊為true就返回true,短路特性 |
true || false |
true |
|
! |
邏輯非 |
取反 |
!true |
false |
|
& |
邏輯與(不短路) |
兩邊都執行,不短路 |
true & false |
false |
|
| |
邏輯或(不短路) |
兩邊都執行,不短路 |
true | false |
true |
|
^ |
邏輯異或 |
兩邊結果不同才返回true |
true ^ false |
true |
💡 短路特性:對於&&,如果左邊為false,右邊就不再執行;對於||,如果左邊為true,右邊就不再執行。這可以提高效率,也可能導致右邊代碼不執行,需要注意。
代碼示例:
public class LogicDemo {
public static void main(String[] args) {
boolean a = true;
boolean b = false;
// 邏輯與 &&
System.out.println("a && b: " + (a && b)); // false
// 邏輯或 ||
System.out.println("a || b: " + (a || b)); // true
// 邏輯非 !
System.out.println("!a: " + !a); // false
// 短路特性演示
int num = 10;
// &&左邊為false,右邊的num++不會執行
boolean result1 = (num > 20) && (num++ > 5);
System.out.println("result1: " + result1 + ", num: " + num); // false, 10
// ||左邊為true,右邊的num++不會執行
boolean result2 = (num < 20) || (num++ > 5);
System.out.println("result2: " + result2 + ", num: " + num); // true, 10
// 不短路的&和|會執行兩邊
int num2 = 10;
boolean result3 = (num2 > 20) & (num2++ > 5);
System.out.println("result3: " + result3 + ", num2: " + num2); // false, 11
}
}
運算符優先級
當一個表達式中有多個運算符時,Java會按照一定的優先級進行計算。記住以下優先級規則(從高到低):
- 括號 ()
- 自增自減 ++ --
- 算術運算符 * / % + -
- 比較運算符 > < >= <= == !=
- 邏輯運算符 ! && ||
- 賦值運算符 = += -= *= /= %=
💡 最佳實踐:不確定優先級時,使用括號()明確運算順序,提高代碼可讀性。
示例:
public class PriorityDemo {
public static void main(String[] args) {
// 優先級示例
int result1 = 3 + 4 * 2; // 先乘後加 → 3 + 8 = 11
System.out.println("3 + 4 * 2 = " + result1);
int result2 = (3 + 4) * 2; // 括號改變優先級 → 7 * 2 = 14
System.out.println("(3 + 4) * 2 = " + result2);
boolean result3 = 5 > 3 && 2 > 1; // 先比較後邏輯與 → true && true = true
System.out.println("5 > 3 && 2 > 1: " + result3);
boolean result4 = 5 > 3 || 2 > 5 && 1 > 0; // &&優先級高於|| → true || false = true
System.out.println("5 > 3 || 2 > 5 && 1 > 0: " + result4);
}
}
類型轉換:不同類型數據的橋樑
Java是強類型語言,不同類型的數據不能直接運算,需要進行類型轉換。類型轉換分為兩種:自動類型轉換和強制類型轉換。
自動類型轉換(隱式轉換)
當把小範圍類型的數據賦值給大範圍類型的變量時,Java會自動完成轉換,這稱為自動類型轉換。就像小杯子的水可以倒進大杯子,不會溢出。
基本數據類型的轉換順序(從低到高):
byte → short → int → long → float → double
char → int(char可以自動轉換為int,因為char本質是Unicode編碼值)
代碼示例:
public class AutoCastDemo {
public static void main(String[] args) {
// byte → int
byte b = 100;
int i = b; // 自動轉換,無需額外操作
System.out.println("byte轉int: " + i); // 100
// int → long
int num = 1000;
long l = num; // 自動轉換
System.out.println("int轉long: " + l); // 1000
// long → double
long bigNum = 123456789L;
double d = bigNum; // 自動轉換
System.out.println("long轉double: " + d); // 123456789.0
// char → int
char c = 'A'; // 'A'的Unicode值是65
int charValue = c;
System.out.println("'A'轉int: " + charValue); // 65
}
}
強制類型轉換(顯式轉換)
當把大範圍類型的數據賦值給小範圍類型的變量時,需要手動進行強制類型轉換。就像大杯子的水倒進小杯子,可能溢出(數據丟失),需要手動操作。
語法:目標類型 變量名 = (目標類型) 源數據;
代碼示例:
public class ForceCastDemo {
public static void main(String[] args) {
// int → byte(可能溢出)
int bigNum = 200;
byte smallNum = (byte) bigNum; // 強制轉換
System.out.println("200強制轉為byte: " + smallNum); // -56(溢出,因為byte最大127)
// double → int(小數部分丟失)
double d = 3.14;
int num = (int) d; // 強制轉換,小數部分被截斷
System.out.println("3.14強制轉為int: " + num); // 3
// long → int(可能溢出)
long l = 12345678901L;
int i = (int) l; // 強制轉換
System.out.println("12345678901強制轉為int: " + i); // 1942913985(溢出)
// 演示溢出原因
System.out.println("byte的最大值: " + Byte.MAX_VALUE); // 127
System.out.println("byte的最小值: " + Byte.MIN_VALUE); // -128
// 200超出byte範圍,二進制存儲時發生溢出,結果變為負數
}
}
⚠️ 強制轉換風險:強制轉換可能導致數據溢出(如200轉byte變成-56)或精度丟失(如3.14轉int變成3),使用時要確保源數據在目標類型範圍內。
常見類型轉換錯誤及解決方法
錯誤1:直接賦值大範圍類型給小範圍類型
// 錯誤示例
int a = 100;
byte b = a; // 編譯錯誤:不兼容的類型: 從int轉換到byte可能會有損失
解決方法:使用強制類型轉換,並確保值在目標類型範圍內:
// 正確示例
int a = 100;
byte b = (byte) a; // 正確,100在byte範圍內(-128~127)
System.out.println(b); // 100
錯誤2:不同類型數據直接運算
// 錯誤示例
int num1 = 10;
double num2 = 3.5;
int result = num1 + num2; // 編譯錯誤:不兼容的類型: 從double轉換到int可能會有損失
解決方法:將結果強制轉換為目標類型,或先將小範圍類型轉換為大範圍類型再運算:
// 正確示例1:強制轉換結果
int num1 = 10;
double num2 = 3.5;
int result1 = (int) (num1 + num2); // 先運算後轉換
System.out.println(result1); // 13
// 正確示例2:提升為大範圍類型運算
double result2 = num1 + num2; // num1自動提升為double,結果為double
System.out.println(result2); // 13.5
錯誤3:字符串與基本類型轉換錯誤
// 錯誤示例
String str = "123";
int num = str; // 編譯錯誤:不兼容的類型: String無法轉換為int
解決方法:使用包裝類的parseXxx()方法:
// 正確示例
String str = "123";
int num = Integer.parseInt(str); // 使用Integer.parseInt()轉換
System.out.println(num + 1); // 124
// 轉換失敗處理(字符串不是數字)
String wrongStr = "abc";
try {
int wrongNum = Integer.parseInt(wrongStr);
} catch (NumberFormatException e) {
System.out.println("轉換失敗:字符串不是有效的整數");
}
💡 包裝類:每個基本類型都有對應的包裝類(如int對應Integer,double對應Double),提供了類型轉換等工具方法。字符串轉基本類型使用parseXxx()方法,基本類型轉字符串可以用String.valueOf(值)或直接拼接空字符串。
類型轉換的實用技巧
- 避免不必要的轉換:能使用自動轉換就不要用強制轉換
- 轉換前檢查範圍:強制轉換前確保值在目標類型範圍內,如:
int a = 200;
if (a >= Byte.MIN_VALUE && a <= Byte.MAX_VALUE) {
byte b = (byte) a;
System.out.println(b);
} else {
System.out.println("值超出byte範圍");
}
- 浮點數轉整數使用Math工具類:需要四捨五入時用Math.round(),而不是直接強制轉換:
double d = 3.7;
int num1 = (int) d; // 3(截斷)
int num2 = (int) Math.round(d); // 4(四捨五入)
綜合案例:數據類型與運算符實踐
下面我們通過一個綜合案例,鞏固今天學習的所有知識點:
public class ComprehensiveDemo {
public static void main(String[] args) {
// 1. 定義各種數據類型的變量
byte age = 25;
short heightCm = 175;
int weightKg = 65;
long phoneNumber = 13812345678L; // 注意加L
float bmi = (float) (weightKg / (heightCm / 100.0)); // BMI = 體重(kg)/身高(m)²
char gender = '男';
boolean isStudent = true;
// 2. 使用運算符計算
int nextYearAge = age + 1;
double heightM = heightCm / 100.0; // 身高轉米
double bmiPrecise = weightKg / (heightM * heightM); // 更精確的BMI計算
// 3. 使用邏輯運算符判斷
boolean isNormalBmi = (bmiPrecise >= 18.5) && (bmiPrecise <= 23.9);
// 4. 輸出結果
System.out.println("=== 個人信息 ===");
System.out.println("年齡:" + age + "歲,明年:" + nextYearAge + "歲");
System.out.println("身高:" + heightCm + "cm (" + heightM + "m)");
System.out.println("體重:" + weightKg + "kg");
System.out.println("BMI值:" + bmi + " (粗略計算)," + bmiPrecise + " (精確計算)");
System.out.println("性別:" + gender);
System.out.println("是否學生:" + isStudent);
System.out.println("BMI是否正常:" + isNormalBmi);
System.out.println("電話號碼:" + phoneNumber);
// 5. 演示類型轉換
System.out.println("\n=== 類型轉換演示 ===");
System.out.println("身高(cm)轉米: " + heightCm + "cm = " + heightM + "m");
System.out.println("BMI精確值轉整數: " + (int) bmiPrecise); // 截斷小數
System.out.println("BMI四捨五入: " + Math.round(bmiPrecise)); // 四捨五入
}
}
運行結果:
=== 個人信息 ===
年齡:25歲,明年:26歲
身高:175cm (1.75m)
體重:65kg
BMI值:21.0 (粗略計算),21.224489795918366 (精確計算)
性別:男
是否學生:true
BMI是否正常:true
電話號碼:13812345678
=== 類型轉換演示 ===
身高(cm)轉米: 175cm = 1.75m
BMI精確值轉整數: 21
BMI四捨五入: 21
總結與練習
今日重點總結
- 基本數據類型:8種基本類型(4整數、2浮點、char、boolean),重點掌握它們的內存佔用和應用場景
- 變量與常量:變量是可變的容器,常量是不可變的值(用final修飾),遵循命名規則
- 運算符:算術、賦值、比較、邏輯運算符,注意優先級和短路特性
- 類型轉換:自動轉換(小→大)和強制轉換(大→小),強制轉換可能導致溢出或精度丟失
課後練習
- 基礎練習:編寫程序,定義不同類型的變量,使用各種運算符進行計算,並打印結果。
- BMI計算器:輸入身高(cm)和體重(kg),計算BMI值並判斷體型(偏瘦<18.5,正常18.5-23.9,超重24-27.9,肥胖≥28)。
- 類型轉換挑戰:思考以下代碼的輸出結果,並解釋原因:
public class ConversionChallenge {
public static void main(String[] args) {
int a = 128;
byte b = (byte) a;
System.out.println(b); // 輸出什麼?為什麼?
char c = '中';
int d = c;
System.out.println(d); // 輸出什麼?代表什麼?
double e = 1.5;
int f = (int) e;
int g = (int) Math.round(e);
System.out.println(f + ", " + g); // 輸出什麼?區別是什麼?
}
}
常見問題解答
Q1:為什麼需要多種數據類型?
A1:為了節省內存空間和提高效率。存儲年齡用byte(1字節)比long(8字節)更節省空間,處理大整數才需要long類型。
Q2:float和double哪個更好?
A2:大多數情況推薦使用double,因為它精度更高。只有在內存緊張(如大量浮點數據)時才考慮float。
Q3:自增運算符i++和++i有什麼區別?
A3:單獨使用時沒有區別,都使i增加1。在表達式中使用時,i++先使用i的值再自增,++i先自增再使用i的值。
Q4:強制類型轉換時如何避免溢出?
A4:可以使用包裝類的MAX_VALUE和MIN_VALUE檢查範圍,如if (num <= Integer.MAX_VALUE && num >= Integer.MIN_VALUE)。
通過今天的學習,我們已經掌握了Java編程的基礎構建塊。明天我們將學習流程控制語句,讓程序能夠根據條件執行不同代碼,實現更復雜的邏輯!