1 Java基礎
1.1 變量
1.1.1 簡介
變量是一個代詞,指代在計算機的內存中的一塊空間,用來存儲程序在運行中所需要的數據。
1.1.2 命名規則
- 只能包含字母、數字、_和$,並且不能以數字開頭;
- 不能使用關鍵字/保留字(是關鍵字的一種,但是占着不用);51+2
- 嚴格區分大小寫(對大小寫敏感);
- 可以是中文、日文、韓文等命名,但不建議,有可能亂碼;
- 建議:英文的見名知意、駝峰命名法,不要使用拼音。
1.1.3 聲明
變量的聲明指的是在內存中開辟一塊指定大小的內存空間,默認還沒有存數據。
語法結構:數據類型 變量名;
// 聲明了一個int類型變量num int num; // 聲明了三個int類型變量a、b、c int a, b, c;
1.1.4 初始化
變量的初始化指的是對變量的第一次賦值。
語法結構:數據類型 變量名 = 值;
1.聲明同時初始化 // 聲明變量num,同時賦值為250 int num = 250; 2.先聲明再初始化 // 聲明變量num int num; // 給num賦值為250 num = 250; 3.同時聲明多個變量(用得較少) // 同時聲明變量a、b、c int a, b, c; // 同時聲明變量a、b、c,並分別賦值為100、200、300 int a=100, b=200, c=300;
1.1.5 訪問(操作)
- 變量在使用之前必須要聲明並初始化;
- 變量的操作必須與類型匹配。
1.2 數據類型
1.2.1 簡介
基本數據類型也叫原生數據類型,Java保留了C語言中的8個基本數據類型,為了計算方便,速度快,但是不能參與面向對象開發。
包裝類S
1.2.2 整數相關
- byte : 字節型,1個字節(8位),-128 ~ 127,用得一般
- short : 短整型,2個字節(16位),-32768 ~ 32767,少到幾乎不用
- int : 整型,4個字節(32位),-2^31 ~ 2^31-1,最常用
- Java中整數直接量默認為int類型,如: 123、250、10000
- 兩個int類型的變量操作,結果還是int類型,小數位無條件舍棄
- long : 長整型,8個字節(64位),-2^63 ~ 2^63-1,用得一般
- long類型的直接量,要在整數后面加l或L,如: 123L、250L
- 如果要計算超出了long范圍的時候,可以使用BigInteger類
1.2.3 小數相關
- float : 浮點型,4個字節(32位),-2^31 ~ 2^31-1,少到幾乎不用
- float類型的直接量,要在小數后面加f或F,如: 3.14F
- double : 雙精度浮點型,8個字節(64位),-2^63 ~ 2^63-1,最常用
- Java中小數直接量默認為double類型,如: 3.14、6.18
- 有可能會出現舍入誤差,精確運算時要慎用,(因為10進制與2進制之間轉換時有可能會損失精度)
- 要做小數的精確計算時,可以使用BigDecimal類
1.2.4 其他類型
- char : 字符型,2個字節(無符號16位),0 ~ 65535
- char類型的直接量,需要放在’’單引號中,單引號中有且僅有1個字符
- 使用Unicode編碼格式,實質上是整數,即char對應的碼,如: A->65,a->97
- ”Java程序員”在內存中占多少個字節?14
- boolean : 布爾型,1個字節(8位),false/true
1.2.5 附:面試題
- Java中的原生數據類型有哪些?各自的范圍是多少?
1.3 基本數據類型的轉換
1.3.1 自動類型轉換,從小類型到大類型
byte --> short --> int --> long --> float --> double --> char
1.3.2 強制類型轉換,從大類型到小類型強轉,有可能發生精度丟失、溢出。向下造型
double d = 3.14; //float f = d; //編譯錯誤,大類型不能直接賦值給小類型 float f = (float) d; //將d中的數據強轉成float類型 int i = (int) d; //強制轉換,i=3,精度丟失 long l = 200; byte b = (byte) l; //強制轉換,溢出了
1.3.3 附:面試題
- 下面的代碼編譯是否正確?
short s1 = 10; short s2 = 20; s1 = s1 + s2; //編譯錯誤,因為short類型的運算結果自動變成int類型
1.4 運算符
1.4.1 算術運算符 + - * / % ++ --
% : 取余/取模,兩個數相除取余數,如: 4/3=商1余1+ 5/3求模
++ : 自增,變量自身加1
++a 先運算后賦值、 a++先賦值后運算
int a = 11; // 先賦值后加1:先把a變量的值10賦給a++表達式(a++=10),然后a變量自身再加1(a=11) int b = a++; Int b=++a; System.out.println(a); //11 System.out.println(b); //10 int x = 10; // 先加1后賦值:x變量先自身加1(x=11),然后再將x變量的值11賦給++x表達式(++x=11) int y = ++x; System.out.println(x); //11 System.out.println(y); //11 int c=5; int f=2;//3 int d=f++; System.out.println(f);//3
-- : 自減,變量自身減1
int a = 10; // 先賦值后減1:先把a變量的值賦給a--表達式(a--=10),然后a變量自身再減1(a=9) int b = a--;//先賦值再減減 System.out.println(a); //9 System.out.println(b); //10 int x = 10; // 先減1后賦值:x變量先自身減1(x=9),然后再將x變量的值9賦給--x表達式(--x=9) int y = --x;//先運算后賦值 System.out.println(x); //9 System.out.println(y); //9
1.4.2 關系運算符 > < >= <= == !=
System.out.println( 10 > 5 ); //true
System.out.println( 10 < 5 ); //false
System.out.println( 10 >= 10 ); //true
System.out.println( 10 <= 10 ); //true
System.out.println( 10 == 10 ); //true
System.out.println( 10 != 10 ); //false
- 關系運算符的結果為boolean類型
1.4.3 邏輯運算符 && || !
&& : 邏輯與/短路與,兩邊表達式都為true,結果才為true,若左邊的表達式為false時會發生短路(右邊的表達式不再執行了)。
|| : 邏輯或/短路或,只要一邊表達式為true,結果就為true,若左邊的表達式為true時會發生短路(右邊的表達式不再執行了)。
! : 非/取反,非真true則假false,非假false則真true
// 判斷是否為閏年:1.年份能被4整除並且不能被100整除,2.年份能直接被400整除 int year = 2020; 3200 boolean b = (year%4==0 && year%100!=0) || year%400==0; System.out.println(“是否為閏年?” + b);
- 邏輯運算符一般配合關系運算符來使用
- 邏輯運算符的結果為boolean類型
1.4.4 賦值運算符 = += -= *= /= %=
= : 普通賦值運算符
+= -= *= /= %= : 擴展賦值運算符
int a = 10;
a += 20; //相當於: a = a + 20;
- 擴展賦值運算符默認有類型轉換的特點
short s1 = 10;
short s2 = 20;
s1 = s1 + s2; //編譯錯誤,short類型運算后的結果是int類型,int不能直接賦給short
s1 += s2; //編譯通過,相當於: s1 = (short) (s1 + s2);
1.4.5 三目運算符
三目運算符也叫三元運算符,因為它是由3個表達式組成的。
語法結構:boolean表達式1 ? 表達式2 : 表達式3;
- 三目運算符的執行過程:
- 先判斷boolean表達式1
- 若boolean表達式1為true,執行:冒號左邊的表達式2,否則執行:冒號右邊的表達式3。 //不建議使用,使用if
// 求兩個數中的最大值
int a = ?;
int b = ?;
int max = a > b ? a : b;
System.out.println(max);
- 三目運算符可以嵌套,嵌套之后使代碼結構不清晰,但是一般不用。
1.4.6 字符串連接符
+ 即可以用來做算數加法運算,也可以用來做字符串的拼接運算。
- 若 + 左右兩邊都是數字類型時,默認做加法運算;
- 若 + 左右兩邊只要有字符串類型時,默認做字符串拼接運行;
- 字符串拼接后,結果還是字符串;
int a = 250;
String s1 = “hello”;
String s2 = s1 + a; // “hello”+250 => “hello250”
String str = 5 + 7 + “abc” + 7 + 5;
System.out.println(str); //”12abc75”
1.4.7 位運算符(擴展)
位運算符是針對二進制運算的,常見的位運算符有以下這些:
- & : 位與,兩邊都是1,結果才是1
- | : 位或,兩邊都是0,結果才是0
- ~ : 位反,~0=1,~1=0
- ^ : 位異或,一邊為1一邊為0時,結果才是1
- >> : 位有符號右移,將二進制整體向右邊移動,前面補0,保留符號位(正/負)
- << : 位有符號左移,將二進制整體向左邊移動,后面補0,保留符號位(正/負)
- >>> : 位無符號右移,將二進制整體向右邊移動,前面補0,不保留符號位,移完后都是正數
1.4.8 附:面試題
- & 和 && 的區別?
& 和 && 都可以用來做邏輯運算
a)&是位與運算符,&&是邏輯與運算符
b)&不會發生短路,&&是會發生短路的
2. 使用最有效的方式計算 8/4 的結果?
8 >> 2
00001000 >> 2 = 00000010
1.5 分支結構
Java編程語言中有三種語法結構,分別是:順序結構、分支結構、循環結構。
分支結構指的是根據條件的判斷去決定是否執行某段代碼,簡單的說就是可以選擇性的去執行某些代碼。
1.5.1 單路分支
單路分支是指如果條件成立了就去執行指定的代碼,否則就不執行。
語法結構:if(條件) { 條件成立時執行的代碼... }
int price = ?; if (price >= 500) { System.out.println(“打8折!”); } //超市、 特殊寫法: if(price >=500) System.out.println(“打8折!”); //不常用
1.5.2 雙路分支
雙路分支是指如果條件成立了就去執行指定的第一段代碼,否則就去執行指定的第二段代碼。場景:一個條件做兩件事情
語法結構:
if(條件) { //true/false
第一段代碼... true
}else{
第二段代碼... flase
}
// 判斷年份是否為閏年
int year = 2020;
if (year%4==0 && year%100!=0 || year%400==0) {
System.out.println(year + “是閏年!”);
} else {
System.out.println(year + “不是閏年!”);
}
1.5.3 多路分支(嵌套分支)
多路分支是指在多個條件的判斷下,去執行其中條件成立指定的代碼。場景:多個條件做多件事情,確定一個范圍
語法結構:
if (條件1) {
代碼塊1
} else if(條件2) {
代碼塊2
} else if(條件n) {
代碼塊n
} else {
代碼塊else
}
// 其實,上面的代碼是下面嵌套代碼的簡寫!
if (條件1) {
代碼塊1
} else {
if(條件2) {
代碼塊2
} else {
if(條件n) {
代碼塊n
} else {
代碼塊else
}
}
}
// 成績等級判斷
int score = ?;
if (score >= 90) {
System.out.println(“A-優秀”);
} else if (score >= 80) {
System.out.println(“B-良好”);
} else if (score >= 70) {
System.out.println(“C-中等”);
} else if (score >= 60) {
System.out.println(“D-及格”);
} else {
System.out.println(“E-不及格”);
}
1.5.4 switch case
switch case 也是用來作為多路分支,優點是速度快,缺點是不夠靈活。場景:確定值的時候(不是一個范圍)
語法結構:
switch(表達式) {
case 值1:
代碼塊1;
break;
case 值2:
代碼塊2;
break;
case 值n:
代碼塊n;
break;
default:
代碼塊default;
}
- switch括號中的表達式結果只能是int和String類型。
- case 后面的值一定要是直接量或常量,不能是變量。
- break 用來中斷switch語句,也就是不要再執行break后面的代碼;注意:如果沒有break的話,case將會出現穿透的效果(會一路執行到switch內部代碼的最后,或是一路執行到后面遇到的break為止)。
// 模擬取款機程序
int cmd = ?;
switch (cmd) {
case 1:
System.out.println(“查詢余額”);
break;
case 2:
System.out.println(“轉賬”);
break;
case 3:
System.out.println(“取款”);
break;
default:
System.out.println(“輸入有誤”);
}
1.6 循環結構
循環指的是反復/重復去執行一段相同或相似的代碼。
1.6.1 while
語法結構:
while(條件) {
循環體代碼塊
}
執行流程:
當條件成立,就會循環執行循環體代碼塊,直到條件不成立為止。
應用場景:
當咱們不知道要循環多少次時,也就是說循環次數不確定時。
1.6.2 do while
語法結構:
do {
循環體代碼塊
} while(條件);
執行流程:
1、先執行一次循環體代碼塊
2、當條件成立,則繼續循環執行循環體代碼塊,直到條件不成立為止。
應用場景:
當咱們要先執行一次循環體代碼塊,再進行循環條件的判斷時。
在實際的開發中,do while循環用的較少。
1.6.3 for
語法結構:
for (表達式1; 表達式2; 表達式3) {
循環體代碼塊
}
說明:
- 表達式1 - 循環變量的初始化
- 表達式2 - 循環的條件
- 表達式3 - 循環變量的改變(注:應該要向着循環結束去改變)
執行流程:
- 先執行表達式1,進行循環變量的初始化操作,注:只執行一次
- 再執行表達式2,進行循環條件的判斷
1) 若條件成立,則執行循環體代碼塊
2) 若條件不成立,則結束循環
- 再執行表達式3,進行循環變量的改變
- 依次第2.和第3.步循環執行
應用場景:
當循環次數固定時,建議使用for循環。
1.6.4 循環的關鍵字
break 是中斷的意思,在循環中使用時,可以使當前循環結束。注:break只能結束一層循環。
continue 是繼續的意思,用在循環中,跳過本次循環continue后面的代碼,從而進入下一次循環。
int sum = 0;
for(int i = 0; i < 10; i++) {
if(i % 2 == 0){
continue;
}
sum += i;
}
int sum = 0;
for(int i = 0; i < 10; i++) {
if(i == 5){
break;
}
sum += i;
}
System.out.println(sum);
1.6.5 循環的嵌套
循環的嵌套指的是在循環中可以嵌套另一個循環,可以多層嵌套,但是開發中循環的嵌套最好不要超過3層。
// 九九乘法表
for(int i = 1; i <= 9; i++) { //循環9次,控制行數
for(int j = 1; j <= i; j++) { //控制列數,列數跟隨行數底層而增加的
System.out.print( i + “*” + j + “=” + (i * j) );
}
System.out.println();
}
說明:
外層循環執行一次,它的內層循環要執行完一輪。
1.7 數組
1.7.1 數組的簡介
- 數組是指一組數據的集合,數組中的每個數據稱作為元素。
- 數組是一種線性表數據結構,它用一組連續的內存空間,來存儲一組具有相同類型的數據。
- 同一個數組中存放的元素的類型必須要一致。
- 在Java中,數組是一種引用數據類型。
1.7.2 數組的聲明
聲明數組是指告訴Java數組的類型是什么。
// 1.中括號[]寫在類型的后面,Java中推薦這種寫法
int[] arr;
// 2.中括號[]寫在變量名的后面
int arr[];
int[][] arr;
int arr[][];
int[] arr[];
1.7.3 數組的初始化
語法結構:
// 先聲明數組
int[] arr;
// 對數組默認初始化
arr = new int[10];
上述代碼相當於在內存中定義了10個int類型的變量,第1個變量表示為arr[0],第2個變量表示為arr[1],以此類推,第10個變量表示為arr[9]。其中的0,1,…,9稱為數組的下標/索引,下標從0開始,到“數組的長度-1”結束。
當然,除了上面初始化數組的方式外,還可以像下面這樣:
// 聲明和初始化寫在一起,數組中默認每個元素的初始化值為0
int[] arr = new int[10];
// 聲明和初始化一起,但是手動指定初始化的值
int[] arr = {1, 2, 3};
// 聲明和初始化一起,手動指定好初始化的值,注意:[]中括號中不能再指定長度
int[] arr = new int[]{1, 2, 3};
問題:int[] arr = {1,2,3} 與 int[] arr = new int[]{1,2,3} 的區別?
int[] arr = {1,2,3} 只能聲明和初始化寫在一起,不能分開寫,如:
int[] arr;
arr = {1,2,3}; //編譯錯誤的
int[] arr = new int[]{1,2,3} 可以聲明和初始化寫在一起,也可以分開,如:
int[] arr;
arr = new int[]{1,2,3}; //編譯成功
1.7.4 數組的訪問
通過下標/索引來訪問元素,數組提供了一個length屬性,來獲取數組的長度(元素的個數)。
int[] arr = {1, 4, 7, 8};
System.out.println(arr.length); //打印數組的長度:4
arr[0] = 100; //給arr中的第1個數賦值為100,此時:[100, 4, 7, 8]
System.out.println(arr[3]); //輸出arr中的最后一個數:8
System.out.println(arr[arr.length-1]); //靈活的輸出arr中最后一個元素
arr[4] = 88; //錯誤的,下標越界/超范圍,ArrayIndexOutOfBoundsException
1.7.5 數組的遍歷
遍歷是指對數組中所有元素的訪問,依次對數組中每個元素訪問一次。
- 順序遍歷
int[] arr = {1, 4, 7};
for(int i = 0; i < arr.length; i++){
int a = arr[i]; //arr[0], arr[1], arr[2]
System.out.println(a);
}
- 倒序遍歷
int[] arr = {1, 4, 7};
for(int i = arr.length - 1; i >= 0; i--){
System.out.println(arr[i]); //arr[2], arr[1], arr[0]
}
- 增強版for循環遍歷
int[] arr = {1, 4, 7};
// a表示每次循環從數組中取出的那個元素,arr表示要遍歷的數組
for(int a : arr){
System.out.println(a);
}
1.7.6 數組的排序
- 自帶排序
int[] arr = {3, 6, 9, 2, 5, 8, 1, 4, 7};
// Arrays.sort(T[] arr) 默認按照升序(從小到大)來排序的
java.util.Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); //打印排序后的數組,[1, 2, 3, 4, 5, 6, 7, 8, 9]
- 冒泡排序(筆試)
int[] arr = {3, 6, 9, 2, 5, 8, 1, 4, 7};
for(int i=0; i<arr.length-1; i++){ //控制趟數
for(int j=0; j<arr.length-1-i; j++){ //控制每趟的次數
//如果當前元素比后一個元素大,則交換位置
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(arr)); //打印排序后的數組
1.7.7 數組的工具類
Java中提供了java.util.Arrays工具類,可以對數組進行排序、檢索、轉換、輸出等操作。
Arrays.sort(arr); //對數組進行排序
int index = Arrays.binarySearch(arr, key); //對數組進行二分查找,注:數組中的元素一定是升序的
String str = Arrays.toString(arr); //將數組轉換為字符串
int[] newArr = Arrays.copyOf(arr, len); //擴容/縮容 數組
1.8 方法
1.8.1 方法的簡介
方法也稱為函數/過程,封裝的一段特定的邏輯功能、有名字的代碼塊。
方法可以使程序結構清晰、便於代碼的重復使用。
1.8.2 方法的定義
語法結構:
修飾符 返回值類型 方法名 ( [參數類型 參數名1, 參數類型 參數名2, ...] ) {
方法體
[return 返回值;]
}
上述代碼的語法格式具體說明如下:
- 修飾符:用於限定方法的聲明,常見的有訪問控制修飾符、靜態修飾符、最終修飾符 等等。
- 返回值類型:用於限定方法返回值的數據類型,為了告訴調用者知道要用什么類型來接收返回結果。
- 參數類型:用於限定調用方法時傳入參數的數據類型。
- 參數名:是一個變量,用於接收調用方法時傳入的數據。
- return 關鍵字:用於結束方法以及返回方法指定類型的值。
- 返回值:被return語句返回的數據,該值會返回給調用者。
方法中的“[參數類型 參數名1, 參數類型 參數名2, ...]”稱為參數列表,表示方法在調用時需要接收的參數,如果方法不需要接收任何參數,則參數列表為空,即()括號內不寫任何內容。
如果方法中沒有返回值,那么返回值類型要聲明為void,方法中的return語句可以省略。
例如:
//無返回值無參數的方法
public static void sayHi() {
System.out.println("Hi");
}
//有返回值有參數的方法
public static int sum(int a, int b) {
int result = a + b;
return result;
}
//封裝冒泡排序算法,方便重復調用
public static void bubbleSort(int[] arr) {
for(int i=0; i<arr.length-1; i++){ //控制趟數
for(int j=0; j<arr.length-1-i; j++){ //控制每趟的次數
//如果當前元素比后一個元素大,則交換位置
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
- 什么時候方法要定義參數?
當方法中要使用到的數據,但是又不能在方法中寫死,那么這時就可以把這些數據先定義為方法的參數,讓調用者在調用方法時再具體傳遞過來,參數可以使得方法變得更加靈活。
- 什么時候方法要定義具體返回值類型?
當方法中邏輯計算完成之后,要返回計算的結果給調用者時,那么就得定義具體的返回值類型。
1.8.3 方法的調用
- 無參無返回值方法的調用
方法名();
System.out.println();
- 有參無返回值方法的調用
方法名(參數值..);
System.out.println(250);
- 無參有返回值方法的調用
數據類型 變量名 = 方法名();
double num = Math.random();
- 有參有返回值方法的調用
數據類型 變量名 = 方法名(參數值..);
double sqrt = Math.sqrt(4);
good luck!
- & 和 && 的區別?