CMoney菁英軟體工程師訓練營第四屆 === ## 2/25(day1) ### 額外 自動化玩具 ifttt、workflow design pattern [非關語言: 設計模式](https://openhome.cc/Gossip/DesignPattern/) ### 命名規則 [命名規則參閱](https://www.javaworld.com.tw/jute/post/view?bid=20&id=27897&sty=1&tpg=1&age=0) Project name 大寫起頭 駝峰式命名 package name 全小寫命名 Class name 大寫開頭 駝峰命名 variable, function name 小寫非數字開頭,駝峰式命名 宣告為final的變數(不可更動值)則全部大寫 ### 變數 小數點預設為double ```java= float f = 3.0f; ``` ```java= int num1, num2; num1 = num2 = 0; ``` 宣告連續變數,程式一律都是右邊開始執行 ### 進制轉換 2->10 10->2 ... ### 字元表示法 ASCII java以Unicode存放char並且是2byte,所以可以存放中文字 ### 強制轉型必要性 省略不必要的位數,過濾資料 ```java= float f = (int)3.66666; System.out.println(f); // 3.0 ``` ### 基本資料型態&參照資料型態 java的基本資料型態包含int(4)、float(4)、boolean(1)、char(2)、double(8)、short(2)、long(8)、byte(1)*(括號內為byte數)* 當宣告基本資料型態變數時,是宣告一個標籤,標籤的位址存放基本資料型態變數的值;而當宣告一個參照資料型態,同樣宣告一個標籤,此標籤存放的值為這個==物件實體的位址==。 ## 2/26(day2) ### 格式化字串 ```java= float f = 1.3333f; System.out.printf("%.2f", f); // 1.33 ``` ### if/else判斷 綜合所得税&累進稅率計算(不同級距採if/else if方式) #### & and && & 表示前後都要判斷 && 若前面的判斷為false,則不需要判斷後面的判斷式,可以省判斷 | and || 也是同樣機制 ```java= // && int a = 80; boolean c = true; boolean d = false; if(a >= 80 && (c = d)){ ... } ``` ### switch case ### 算術指定運算子 需考量優先級 ++ 與 小括號 同級別,故從左而右算 ```java= a += 1; a++; // 先給後加 ++a; // 先加後給 ``` ```java= int a = 1; int b = 0; b = a++; // a = 2 // b = 1 ``` ```java= int a = 1; int b = 0; b = ++a; // a = 2 // b = 2 ``` ```java= int a = 1; int b = 0; b = a++ + ++a; // 1 + 3 // a = 3 // b = 4 ``` ```java= int c = 0; int b = 0; while(c < 3){ b += ++c; } System.out.println(b + " " + c); // 6 3 ``` ```java= int c = 0; int b = 0; while(c < 3){ b += c++; } System.out.println(b + " " + c); // 3 3 ``` ### 進制轉換 10 -> 2 2 -> 8 將二進制3數為一組 2 -> 16 將二進制4數為一組 ## 2/27(day3) ### while / for 可於迴圈中加入變數當作計數器,用以計算迴圈重複的次數。 ### do while ```java= Scanner scanner = new Scanner(System.in); int n; do{ n = scanner.nextInt(); }while(n != -1); ``` #### 星狀圖 各式圖形、倒三角、直角三角、等腰三角、菱形... 1. 空心平行四邊形 ```java= int n = scanner.nextInt(); for(int i = 1; i <= n; i++){ // 做空格 for(int j = 0; j < n - i; j++){ System.out.print(" "); } for(int j = 1; j <= n; j++){ if(i > 1 && i < n && j > 1 && j < n){ System.out.print(" "); }else{ System.out.print("*"); } } System.out.println(); } ``` 2. 實心菱形(兩塊) ```java= //上半塊 for(int i = 1; i <= n; i++){ for(int j = 1; j <= n-i; j++){ System.out.print(" "); } for(int j = 1; j <= 2*i-1; j++){ System.out.print("*"); } System.out.println(); } //下半塊 for(int i = n+1; i <= 2*n-1; i++){ for(int j = 1; j <= i-n; j++){ System.out.print(" "); } for(int j = 1; j <= 4*n-1-2*i; j++){ System.out.print("*"); } System.out.println(); } ``` 3. 實心菱形(一塊) :::info ==絕對值==想法實作 ::: ```java= int n = scanner.nextInt(); for(int i = 1; i <= 2*n-1; i++){ for(int j = 1; j <= (int)Math.abs(n-i) ; j++){ System.out.print(" "); } for(int j = 1; j <= (2*n-1)-(int)Math.abs(2*(i-n)); j++){ System.out.print("*"); } System.out.println(); } ``` 4. 空心菱形 ```java= int n = scanner.nextInt(); for(int i = 1; i <= 2*n-1; i++){ // 左方空白(倒直角三角、直角三角) for(int j = 1; j <= (int)Math.abs(n-i) ; j++){ System.out.print(" "); } System.out.print("*"); // 左方星號 // 第2到第2*n-1層 // 中間空白部分 // 以正中為主分割兩邊 // 左方空白數從0到n-2 // (n-2)-Math.abs(i-n) 層數距離n越遠,空白數越少,故為減數 // 正中空白數固定1個 // 右方空白數與左方同樣,乘2即可 if(i > 1 && i < 2*n-1){ for(int j = 0; j < 2*((n-2)-Math.abs(i-n))+1; j++){ System.out.print(" "); } System.out.print("*"); //右方星號 } System.out.println(); } ``` ## 3/4(day4) ### 陣列 是一個參考資料型態,會於heap當中創造連續記憶體空間,用以存放型態相同的資料,所以存放的地址即為“第1個元素的位置(index = 0)” 所以array在搜尋資料的速度很快,直接加上“第幾筆*宣告的資料結構大小”,即為第幾筆資料的記憶體位址。 ```java= int nums[] = new int[5]; // 有一個叫做 nums 的標籤 // stack存放的值為new出的實體的記憶體空間位址 // 這個值也同樣是 陣列第一個元素的記憶體位址 ``` :::info **nums 與 nums[0]的差異** nums -> addr's value (整個陣列) nums[0] -> value(stored in addr) (值) ::: ==當我們創建了一個**參考資料型態**的陣列,每個陣列值存放的是這群實體各自的記憶體位址== ```java= // example NewClass[] nc = new NewClass[5]; // nc的stack 存放 new NewClass()建立的實體的記憶體位址 System.out.println(nc); // [Lcmoneyclass.NewClass;@1540e19d System.out.println(nc[0]); // null // 仍須各自new出新的記憶體空間來指派給各自的值 // 並非同時new出多個實體 ``` ## 3/5(day5) ### 函式function 類似功能寫成函式,更動的數值設計為變數。 #### 靜態方法static 不需類別物件實體即可使用的方法 #### 技巧:利用return將void函式強制回傳 可以適用於多層巢狀迴圈的打斷(將巢狀迴圈包裹於void函式中),因為可能在內部迴圈結束時即break出此巢狀迴圈,但break只能跳出最近的迴圈,無法跳出外部的迴圈。 #### 傳值呼叫 ![](https://drive.google.com/uc?export=view&id=1qDlMjxZ90SnNzNM6dywva8MAdel1g_HM) ```java= int a[] = new int[2]; a[0] = 1; a[1] = 2; func(a); System.out.println(a[0]); // 5 ``` ```java= public static void func(int b[]){ // 新開了一個b[]的標籤,存放傳入的a陣列地址 // 所以更動此地址所指的記憶體空間 // 同樣會影響到原有a陣列 b[0] = 5; } ``` ## 3/6(day6) ### 排序 1. bubble sort ```java= public static void bubbleSort(int[] arr){ // 找出第幾大的數字 第1次第1大 第2次第2大... 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]){ swap(arr, j, j+1); } } } } ``` 2. insertion sort 3. selection sort ##### 問:利用XOR來實現變數互換? [如何交換兩個變數,而不動用第三個變數?](http://clifflin123456.pixnet.net/blog/post/44902733-%E5%A6%82%E4%BD%95%E4%BA%A4%E6%8F%9B%E5%85%A9%E5%80%8B%E8%AE%8A%E6%95%B8%EF%BC%8C%E8%80%8C%E4%B8%8D%E5%8B%95%E7%94%A8%E7%AC%AC%E4%B8%89%E5%80%8B%E8%AE%8A%E6%95%B8%3F-%E5%88%A9) 主要想法來自於兩個變數的二進制,不需要額外的變數即可達到變數交換的效果。 > example : > x = 5 = 101 > y = 6 = 110 > > 兩數使用XOR來做交換 > x = x XOR y = 011 = 3 > y = x XOR y = 101 = 5 > x = x XOR y = 110 = 6 > > > x = 6 > > > y = 5 ### 隨機數 利用Math.random()函數可用來設定隨機數字。 ```java= Math.random() // return a float between 0 to 1 ``` * 實例應用:選取一個範圍中的隨機數 想法:因為Math.random()會回傳0~1之間的隨機小數,0與1之間的間隔為1,要將此間隔擴大至所需的範圍+1,所以乘以範圍再加上最小值進行平移。 ```java= public static int randomNum(int min, int max){ return (int)(Math.random()*(max-min+1))+min; } ``` * 實例應用:創建一個儲存值亂序的陣列 想法:首先設定一個內容值為其索引值的陣列,接著將針對其中第i個值,從剩下(num-i)個值中隨機抽取出一個做調換。 ```java= public static int[] getRandArr(int num){ int[] randArr = new int[num]; // set value for(int i = 0; i < num; i++){ randArr[i] = i; } // 第 i 張牌與後方隨機(num-i)張牌互換 for(int i = 0; i < num; i++){ swap(randArr, i, getRandNum(i+1, num)); } return randArr; } ``` ### 課堂練習 1. 成績排序(by座號)(by成績) 2. 排亂順序輸出 3. 撲克牌發牌(不重複值亂序陣列) ## 3/7(day7) ### 多維陣列 在java中,是以一個一維陣列的各個元素各自指向其他的一維陣列。表示第一個一維陣列存放各自指向的一維陣列的位址。 ```java= // 先開一個大小為3的一維陣列 // 存放大小為4的一維陣列的位址 // 大小為4的陣列存放實際的值 int[][] array = new int[3][4]; ``` 在記憶體操控方面會相較C語言的其中一種方式("直接開一個要的大小"&與"java相同機制")更為靈活,能夠配置空間較小的多個陣列實體。 #### 陣列記憶體控制 * 倍增一維陣列存放空間 ```java= public static void main(String[] args){ int[] nums = new int[5]; } public static int[] doubleArr(int[] arr){ int[] tmpArr = new int[arr.length*2]; for(int i = 0; i < arr.length; i++){ tmpArr[i] = arr[i]; } // arr = tmpArr; // 這行表示將arr陣列指向新開的tmpArr陣列位址 // 但此時nums仍指向原有的nums陣列實體 return tmpArr; } ``` :::info Q:**為什麼需要將欲改變大小的陣列位址回傳?傳入陣列來做操作不是就是針對傳入地址的陣列來做改變了嗎?** A:當傳入一個陣列,會在stack中新增一個標籤(arr)來指向原有的陣列位址,而我們需要一個新的2倍大小的陣列時,必須在heap中新開一個兩倍大小的陣列實體,並用新的標籤(tmpArr)去指向這個實體,再將原有的數值一一複製過去,最後回傳兩倍大小陣列實體的位址回去。 如果只將新開的標籤(tmpArr)所存的位址重新指派給原先指向陣列的標籤(arr),則原先的標籤(nums)所指向的位址仍非兩倍大小的陣列實體。(如圖一) (圖一)![](https://drive.google.com/uc?export=view&id=1J1etN-SbtOjDfwHhL5l8MaSW9w8zGy5A) ::: * 倍增二維陣列存放空間(第二維其中一個) 假如想要只倍增nums[2][2]的第二維空間大小,則不需要將陣列位址回傳也可以。 原因在於,當我們傳入一個想要倍增第二維空間大小的二維陣列,我們不需要針對第一維存放的位址做任何的改變,只要創建出新的兩倍大小的一維陣列來將數值重新指派即可。 如圖二的步驟。 :::success ==step1==:原先的nums標籤指向一個大小為2的一維陣列實體,分別存放一個大小為2的一維陣列地址。 ==step2==:將欲倍增的陣列傳入,會先宣告一個arr的二維陣列標籤指向nums所指向的陣列實體。 ==step3==:再宣告一個一維陣列標籤tmpArr來指向兩倍大小的新陣列實體。 ==step4==:分別將原有陣列的值指派給倍增的陣列。 ==step5==:最後將倍增大小的陣列地址指派給欲擴增的的陣列。(原先指向的陣列實體,會交由gc機制來做回收。) ::: (圖二)![](https://drive.google.com/uc?export=view&id=1-3nCouO2x8JlBARt-niZzMLHz0VNiP7e) ```java= public static void main(String[] args){ int[][] nums = new int[2][2]; } public static void doubleArrr(int arr[][]){ int[] tmpArr = new int[arr[0].length*2]; for(int i = 0; i < arr[0].length; i++){ tmpArr[i] = arr[0][i]; } arr[0] = tmpArr; } ``` * 倍增二維陣列存放空間(全部)(假設每個大小都相同)(2x2->4x4->8x8...) ==想法==:直接開一個,再將值複製過去。 ```java= public static void main(String[] args){ int[][] nums = new int[2][2]; } public static int[][] doubleArrrr(int[][] arr){ int[][] tmpArr = new int[arr.length*2][arr[0].length*2]; for(int i = 0; i < arr.length; i++){ for(int j = 0; j < arr[0].length; j++){ tmpArr[i][j] = arr[i][j]; } } return tmpArr; } ``` * 倍增二維陣列存放空間(第一維) ==想法==:將第一維擴大,再將擴大的地方new出新的空間asign回去。不然第一維擴大的部分沒有新的空間指向他。 ```java= public static int[][] doubleArr(int[][] arr){ int[][] tmpArr = new int[arr.length*2][]; for(int i = 0; i < arr.length; i++){ tmpArr[i] = arr[i]; } for(int i = arr.length; i < arr.length*2; i++){ // 倍增的部分再new出新的實體給他 tmpArr[i] = new int[arr[0].length]; } return tmpArr; } ``` ## 3/8(day8) * 課中練習檢討:擴增陣列存放學生資料並排序 * 額外練習講解:1A2B猜數字遊戲(手動猜&電腦猜) ### 1A2B猜數字(手動猜) ==想法==:問題拆解成許多小問題,像是需要check每一次有幾A幾B、將數值各個位數以陣列存放、判斷是否有重複數字的四位數字... ### 1A2B猜數字(電腦猜) ==想法==:每次先猜1234,或是接著猜5678,當有第一次的AB數量時,從所有可能的答案中找出同樣AB數量的答案,再從這些篩選過的答案中去隨機猜,每次都去核對AB數量,再次剔除掉AB數量不同的答案,使隨機猜的範圍逐漸變小,重複直到猜中。 ### 練習:讀取字串並計算字串數量 #### 利用array實作dictionary dictionary可以關鍵字來查詢特定位置的資料,在其他語言中,可以透過給予key值來查找這個key值身上的資料,在此以array的方式來實作。 ==實作想法==: ```java= // 陣列初始大小 String[] strings = new String[2]; // 陣列實際存有值的數量 int count = 0; // 關鍵字陣列(不重複) String[] dictionary = new String[2]; int[] nums = new int[2]; // 紀錄每個關鍵字的數量 int j; int dictionaryCount = 0; // 記錄dictionary中值的數量 for(int i = 0; i < count; i++){ for(j = 0; j < dictionaryCount; j++){ if(dictionary[j].equals(strings[i])){ nums[j]++; break; } } // 表示有新的字典關鍵字需要加入 if(j == dictionaryCount){ dictionary[j] = strings[i]; nums[j]++; // 加入的關鍵字數量設為1 dictionaryCount++; } // 倍增陣列存放空間 if(dictionaryCount == dictionary.length){ dictionary = doubleStringArr(dictionary); nums = doubleIntArr(nums); } } ``` ## 3/11(day9) * test2 ### 字串 * ASCII code * 字元 & int 互換 * String Pool 在heap中有一個特別的空間(String Pool),用來存放所有傳入字串的地址。 ex: String Pool中存有"123"這個字串 ```java= String a = "123"; String b = "1" + "23"; System.out.println(a == b); // true ``` ```java= String a = "123"; String b = new String("123"); System.out.println(a == b); // false ``` 所以當要比較兩個字串值是否相等,必須使用String.equal()方法。 ### 字串物件的方法 * split() 給予切割字元,切出一個string array * substring(start, end) 切出起始位置到結束位置-1的值,總計(end - start)字元。 * 其他 可參閱 7.3 ppt or 上網查 ### 遞迴 #### 費氏數列(遞迴)(非遞迴)寫法 ==*遞迴版本*== ```java= public static int fibonacciByRecursion(int num){ if(num == 1) return 1; if(num == 0) return 0; return fibonacciByRecursion(num-1) + fibonacciByRecursion(num-2); } ``` ==*非遞迴版本*== ```java= public static int fibonacciByForLoop(int num){ // 陣列大小為費氏數+1的原因在於 f(0)=0 // 當想要求f(10)時,實際上需要10+1個空間大小 int[] nums = new int[num+1]; // 藉由陣列來存放每個費氏數的值 for(int i = 0; i < num+1; i++){ if(i == 1) nums[i] = 1; if(i == 0) nums[i] = 0; if(i > 1){ nums[i] = nums[i-1] + nums[i-2]; } } return nums[num]; } ``` #### 河內塔 有n個盤子和三座塔(A、B、C),需要將盤子從A塔移到C塔,其中每個盤子上都有各自的編號,移動的過程必須符合以下規定:一次動一個盤子,編號大的盤子不能疊在編號小的盤子上。 ==遞迴想法==: 主要分成三個步驟: 步驟一:首先將(n-1)個盤子從A塔移動至B塔。 步驟二:再將剩下的那個最大盤子從A塔移動至C塔。 步驟三:最後將B塔的(n-1)個盤子從B塔移動至C塔。 base case:當只有1個盤子時,印出移動過程。 ```java= public static void hanoi(int plate, char start, char terminal, char tmp){ // base case if(plate == 1){ System.out.println("from " + start + " to " + terminal); return; } hanoi(plate-1, start, tmp, terminal); // step 1 hanoi(1, start, terminal, tmp); // step 2 hanoi(plate-1, tmp, terminal, start); // step 3 } ``` ## 3/12(day10) ### 函式多載(overloading) 相同函式名稱可以同時存在,但給予的參數必須不同,且回傳值的類型必須相同。 舉例:swap()方法,用來交換一維或是二維陣列,傳入不同維但可以同樣實現交換的方法。 ### 物件導向 任何物件都在類別之下,身上具有屬性及方法,與一般結構式語言(C/C++)不同,缺點可能在於效能會差一點,但好處在於易於程式設計。 #### static靜態方法 與類別相同層級,不需要有類別的實體即可使用的屬性或方法。 #### 封裝(encapsulation) 封裝性適用於將設計好的類別給別人使用時,給予不同的權限設計,用來避免設計好的類別內容遭人更改。 * public * private * protected * default 但可藉由setter/getter來間接存取修改屬性值。 #### 建構子(constructor) 當物件實體產生時,會自動執行的方法,用來將傳入參數指派給物件身上的屬性。當不寫建構子時,會自動產生一個空的建構子。若當創建了建構子時,空的建構子會被刪掉,若有空建構子的需求,必須再自行創建。 建構子也有overloading的概念,所以可以創建多個不同參數的建構子。 *若要傳入陣列當作參數,不要將空間在類別中new出來,在建構子中設計。* #### this關鍵字 this關鍵字在執行時是指現在這個類別操作的物件實體,而在類別中寫到這個關鍵字則是表示這個類別本身,所以我們可以將傳入參數帶入此物件身上的屬性。 ```java= /* MyClass.java */ public class Myclass(){ int width; int height; // 建構子 public MyClass(int w, int h){ this.width = w; this.height = h; } } ``` ```java= public class Tester(){ public static void main(String[] args){ MyClass mc = new MyClass(5, 3); System.out.println(mc.width); // 5 System.out.println(mc.height); // 3 } } ``` #### toString() 當使用System.out.print()方法時,會將傳入的物件,呼叫他身上toString()方法,將非String的值,回傳成String,所以可以修改身上的toString()方法,來將物件想要印出的內容印出,否則會印出此物件的地址。 ```java= /* main */ public class Main{ public static void main(String[] args){ NewClass nc = new NewClass(); System.out.println(nc); // nc地址 } } ``` ```java= /* NewClass */ public class NewClass{ /* attributes... * constructor... * */ public String toString(){ String strings; strings = attribute1 + " " + attribute2 + " "; return strings; } } ``` 將我們在類別中設定自己的toString()方法,實際上是複寫(overide)了object最上層類別的方法,就可以印出自己想要輸出的東西。 #### 物件陣列 ```java= Student[] students = new Student[10]; // 創建出一個10格的陣列空間想要用來存放學生物件的地址 // (內容都為null,還沒有學生物件的實體) students[0] = new Student("kj", "大象", 100, 98, 99); ``` 如下圖所示:(實際記憶體配置狀況) ![實際記憶體配置狀況](https://drive.google.com/uc?export=view&id=1qRsYfZOcinZppGUeB5-16Gyn0fWlBJdd) 所以當我們要存取或是寫入類別物件陣列的元素時,必須先將他new出來。 ## 3/13(day11) * 學生類別實作講解 * 加入學生陣列類別改寫 將分工細分 類別設計中,可以在類別中宣告自己的類別,也能夠在方法中傳入自己的類別,只是在設計上要小心。 而在封裝等級上,若如入自己類別的參數,能夠直接取得private的參數,而不需要透過getXXX()的方法,因為類別相同而層級相同。 ```java= public class Rectangle(){ int width; int height; public Rectangle(int w, int h){ this.width = w; this.height = h; } // 比較兩長方形大小 public int compare(Rectangle rectangle){ if(this.getArea() > rectangle.getArea()){ return 1; }else return 0; } } ``` * 出牌遊戲實作 * Uno ## 3/14(day12) * 出牌遊戲實作 * Uno ### String.next()與String.nextLine()的差別 ## 3/15(day13) ### 課堂實作講解 #### static ==好用,但不可濫用。== 在類別實體建成之前就開了一個空間給static屬性或方法,當我有多個類別實體,全部都共用同一個static空間,所以若是其中一個物件更改了static屬性或方法,同樣類別的所有物件的static屬性或方法都會被修改。 通常使用於不會更動的常數屬性或方法。 ### final 不可更動的屬性,必須在建立時即初始化。 ## 3/18(day14) * 測驗3 * 講解測驗3 ## 3/19(day15) ### 繼承 取得父類別屬性在類別中採用super關鍵字來表示父類別。 父類別建構子會比子類別建構子優先執行,而當父類別具有不為空的建構子時,必須在子類別的建構子中呼叫父類別建構子,將父類別建構子的事情先做完,才會做子類別的建構子。 所以==父類別建構子必須寫在子類別建構子的第一行,確保父類別要做的事情都先做完。== ### 繼承的屬性 當繼承自父類別的屬性要取用時,一般都以super.getter()方法來做取用,而當子類別中也有同名屬性時,父類別的屬性會隱藏,但仍佔有記憶體空間,在調用時以this和super來做區別。 ### Override 當我們複寫方法時,回傳值的型態受到規範,也就是說可以回傳原先類別,或是繼承自原先類別的子類別型態,因為子類別繼承自父類別,應該可以達成所有父類別能夠完成的事情。 而複寫(Override)與多載(Overloading)的差別在於複寫是將父類別的方法來做改寫,一般會加上"@Override"來告知系統;而多載是相同名稱的方法具有不同的傳入參數。 ***以String.toString()來做範例*** ```java= @Override public String toString(){ return "這是Override"; } ``` ```java= public String toString(int num){ return "這是Overloading" + num; } ``` ## 3/20(day16) ### Object類別 所有物件都會繼承的父類別,在java中也是唯一一個沒有父類別的類別。當一個類別沒有繼承任何類別時,系統會自動繼承Object類別。 ### 多型 父類別物件可以以子類別的物件實體來儲存,因為子類別的物件實體中必定包含父類別物件的實體。 #### downcasting ```java= Shape[] shapes = new Shape[2]; shapes[0] = new Rectangle(3, 5); ``` #### 多型應用範例 ```java= // shape父類別 Shape[] shapes = new Shape[5]; shapes[0] = new Rectangle(3, 5); shapes[1] = new Circle(5); shapes[2] = new Rectangle(1, 7); shapes[3] = new Circle(3); shapes[4] = new Rectangle(7, 9); ``` ## 3/21(day17) * 生態系實作 ## 3/22(day18) ### 泛型 在Java中已經先幫我們實作出一些資料結構,可以直接使用身上的方法,而不需要自己去寫doubleArr()、getCount()之類的方法。 以ArrayList來做說明,<>在這個diamond符號中的類別,表示這個ArrayList中能夠存放的類別, ```java= ArrayList<Integer> nums = new ArrayList<>(); nums.add(3); nums.add(2); nums.add(1); ``` ### 資料結構(array、linkedList) * array 連續記憶體空間, * linkedList 不需連續的記憶體空間 ```java= // 實作 // 包含 add()、remove()、get()、insert()、size()方法 ``` ## 3/25(day19) * test4 筆試:記憶體管理、進制轉換、手寫程式碼(卡牌) 上機:形狀類別 & 高鐵購票系統 ## 3/26(day20) * test4檢討 ### 檔案管理 * BufferedWriter * BufferedReader > *增加效能的作法為減少與外面檔案io的次數* java中採用==buffer緩衝區==的做法增加效能,先將一定大小的資料流存進緩衝區,等到需要用到時才從緩衝區將資料拉進來處理,可以減少與外頭檔案io的次數。*緩衝區在記憶體中、外頭檔案在硬碟中* ::: warning 記得每次開啟檔案讀取或寫入完成後都要將檔案關閉。 ::: ***在實際使用時,通常都是將檔名傳入寫/讀檔案的function,在function中新建BufferedWriter、BufferedReader來做處理。 而在檔案存讀取的時候,盡量先將資料先存入預想的資料結構中,若是之後還有處理檔案的需求則能夠直接使用這些資料,待所有處理都結束時才將檔案寫入。*** ## 3/27(day21) ### 檔案管理系統練習 * 學生資訊系統 * 捷運系統 ## 3/28(day22) * 捷運系統 ## 3/29(day23) * 捷運系統 ## 4/1(day24) * test_5 ### 介面(Interface) 其中只能有常數以及抽象方法,方法教給時做這個界面的類別來實作。較常使用於責任歸屬的區分上,介面能夠實現多種抽象方法,讓實作同一個介面的類別能夠達成不同的方法。 interface : ```java= ``` * slime史萊姆戰鬥 ## 4/2(day25) ### 內部類別 若是此類別只服務特定的類別,例如LinkedList中的Node,可以將此類別寫在LinkedList類別其中。需要上層類別的實體才能建構出此內部類別的實體。 ### 靜態內部類別 若有需要直接取得內部類別,可以將內部類別設置為靜態方法,可以讓其不需要外部類別實體即可創建。 ### 匿名內部類別 當我們需要一個類別來實現實作介面,但此類別只被使用到一次,我們可以直接在需要使用它的地方,創建出一個匿名類別實體直接實現介面的實作,但不需要直接開一個新的類別給他。 * 進階史萊姆戰鬥 ## 4/3(day26) * 進階史萊姆戰鬥 * LinkedList講解 & 技巧 ***ArrayList & LinkedList差別以及優缺*** * ArrayList 查找快 * Linkedist ## 4/8(day27) * test6 * 加總計算(遞迴、讀寫檔練習) ## 4/9(day28) ### java動畫與繪圖 ### Adapter 是一個實現了多個介面的類別,可以繼承這個類別來選擇自己想要改寫的介面方法,才不需要通通實現。(如果自己實現這些介面會讓整體程式碼變得太過雜亂) ### 共同類別存放共通屬性 圖片的座標、繪製出來的方法 :::info **若將圖片檔存在共通的類別呢?** *共通的類別不會存圖檔,可以交給繼承此類別的子類別來存 若有許多相同怪物使用同一張圖 -> 可以採用static來存圖片 但若是有許多不同的怪物,則需要有不同的類別來各自存放,但行動都一樣,卻需要開這麼多類別... 比較好的做法是 將圖片共同存入一個資源庫 只要有使用到圖片的時候,就將存放圖片的位置回傳* ::: ## 4/10(day29) * java動畫與繪圖 * 隨機生成 & 碰撞 & 射擊 * KeyEvent類別用法 ## 4/11(day30) ### 解決ImageIO重複讀取檔案效能問題 * 可以採用static(但換圖會出問題) 若是同一個角色類別會運用到不同張圖,則會將圖一起換掉。 * 資源管理器(類別) 這個類別中會存放共同的資源, ## 4/12(day31) * RPG製作練習 ## 4/15(day32) * abstract class 抽象類別 ## 4/16(day33) ### 版本控制 * BitBucket & SourceTree ## 4/17(day34) * 期中專題 ## 4/18(day35) ### 例外處理 * Error 嚴重的系統錯誤,通常不處理,直接拋出錯誤訊息。 * Exception 通常不為系統所發生的錯誤,多數來自變數或執行上才發生的例外。 #### try...catch...finally 用來處理有可能發生例外的狀況。 ```java= try{ // (預計要做的事情) // 有可能會發生例外的狀況 // 當狀況發生時,直接拋出例外 // 拋出例外程式碼以下的程式碼不會被執行到 } catch(MyException e){ // 當接到此例外時,做處理 } finally{ // 無論如何都會執行的部分 // 即便在try或catch之中已經有return // 同樣會執行 } ``` * Example ```java= try{ System.out.println("try"); throw SomeException; System.out.println("not reach"); } catch(SomeException e){ System.out.println("deal with exception"); return 0; } finally{ System.out.println("finally"); return 1; } // try // deal with exception // finally // return回去的值 "1" ``` :::info **多型 可能會遇到狀況** * 當在父類別的方法中嘗試拋出例外,在子類別的方法中,若是改寫了父類別的此方法,若是同樣可能會拋出例外,沒辦法去拋出父類別設定的例外層級以上的例外,只能拋出父類別拋出例外層級之下的例外(繼承自父類別例外的子例外)。 * 原因在於若有多個子類別去改寫這些方法,可能會拋出不同的例外,若是此例外不屬於父類別例外的子例外,則無法接受設定的處理,==不在父類別例外的處理範圍中了==。 ::: * Example ```java= // 父類別 public class Shape { // 自己設計的例外 public class SomeException extends Exception{ public SomeException(String msg){ super(msg); } // 父類別中可能會拋出例外的方法 public int getArea() throws SomeException{ System.out.println("try"); throw new SomeException("there is something wrong"); } } ``` ```java= // 子類別 public class Rectangle extends Shape{ // 改寫父類別中可能會拋出例外的方法 // 可以不拋出,若要拋出 // 必須拋出父類別拋出的例外層級以下或相同的例外 @Override public int getArea() throws SomeException{ throw new SomeException("例外的子類別"); } // 拋出父類別可能拋出層級的例外會報錯 // @Override // public int getArea() throws Exception{ // throw new Exception(""); // } } ``` ## 4/19(day36) * 遊戲專題 ## 4/22(day37) ### 測驗8講解 StringArrayList與StringLinkedList以介面(Iterator)及抽象類別(List)實作,並加入concat()方法設計。 ### 泛型 只能夠將型別宣告為參考資料型態,不能宣告為基本基料型態。 #### 以泛型實作LinkedList * 自己練習 ### Stack :::info 一般程式執行時,即是創建了許多系統的stack來記錄執行的順序以及回傳的地址。 而遞迴之所以慢,就是創建了許多stack,等到執行到終止條件時,逐漸將回傳值一個個pop()回來。 ::: stack中主要包含push()、pop()兩種方法 push():將資料加入stack中。 pop():將頂端資料取出回傳,並從stack中移除。 ==額外方法== peek():傳回頂端資料,但不將資料從stack中移除。 * 可實際應用於 "上一頁下一頁"的機制 * 走迷宮練習 ```java= // 迷宮路徑搜尋 // ``` ## 4/23(day38) * 遊戲專題 ## 4/24(day39) * 期中專題階段發表 (待補) 1. 需要修改的部分... 共通問題: 1. 扣緊故事 2. 遊戲說明 3. 分工詳細說明 4. 簡報前後呼應,要有完整性 ## 4/25(day40) * 遊戲專題 ## 4/26(day41) * 遊戲專題 ## 4/29(day42) * test9 ### Queue 通常會應用於"執行緒"相關。 :::info 例如:購票系統 or 網路request 當許多的request進入到系統中,不可以出現超賣票卷的情況,因此只要加進queue之中再慢慢處理即可,後續超過的部分就不處理。 ::: #### queue處理方式 以ArrayList來實現會有front和rear重疊的情況,無法新增值,但queue卻為空的情形。 * 環狀queue來處理 ## 4/30(day43) ### 雜湊Hashing 查找對應內容速度最快:O(1) 經由hash公式換算出對應的記憶體位置,直接去記憶體位置拿資料。 #### 理想Hashing #### Hashing 碰撞 & 溢出 :::info 討論 * 如何選擇 hash function(降低碰撞) * 如何處理 Overflow) * 如何設定 hash table 的大小 ::: #### 數位簽章 * Token 當使用者傳送帳號密碼給伺服器端,伺服器端會將id、時間戳記以及傳送request後拿到的hash值,打包成一個Token,回傳給使用者,讓使用者接下來不需要再打密碼就能夠使用服務,只要回傳token,伺服器端就能確認使用者是本人。 ## 5/2(day44) * 遊戲專題 demo day ## 5/3(day45) * 遊戲專題 ## 5/6(day46) * Test10 - Queue & Stack 實作應用 * Android Studio 安裝 ## 5/7(day47) ### Android Studio package name是在googleplay商店上架用來識別有無重複的依據。也同樣是專案在電腦中的檔案架構。 ### activity簡介與生命週期 ![](https://i.imgur.com/TUqzuzJ.png) ### XML檔案與LinearLayout 是一種文本格式,跟json相同。Andriod Studio會依據此XML文件來生成對應的程式碼。 在Android中所有的元件都是View的子類別(比較像是Component的概念),都會在一個Container中。 ### Margin & Padding Margin與元件的外間距 Padding與元件的內間距 ### Weight 依據所有元件的比重來分配自己在剩餘空間的大小 * weightSum ### Id 透過id來將java檔與xml文件做連結。 ## 5/8(day48) ### Andriod Studio基礎元件 ### Memory Leak 記憶體流失 ## 5/9(day49) ### Json #### JsonObject #### JsonArray ### SharedPreference ## 5/10(day50) * 遊戲專題 ## 5/13(day51) * test11 - Android Studio 拉畫面 ## 5/14(day52) * 遊戲專題 ## 5/15(day53) * 遊戲專題 * 期中發表彩排 ## 5/16(day54) * 最後衝刺 ## 5/17(day55) * 期中遊戲專題發表 ## 5/20(day56) * test12 ### 二元搜尋法(binary search) 適用於已經排序好的陣列 :::info 要怎麼從雜亂數列中找到數? 視情況而定or直接找最快 ::: ### 樹狀結構 ### 二元樹 ### AVL Tree ## 5/21(day57) * 模擬面試 ## 5/22(day58) ### 排序法 Sort 內部、外部排序 #### 各種搜尋法 * insertion sort * selection sort * quick sort * merge sort * * natual merge sort 切分出已經排好的片段,再將片段合併。 * heap sort ## 5/23(day59) * natural merge sort實作 ## 5/24(day60) * natural merge sort實作 ## 5/27(day61) * test13 * 模擬面試 * 話題不要發散,回答問題只給答案就好,對方有興趣再說明 * 履歷寫到的點都需要跟應徵的工作有連結 ### Shared Preference 用來儲存少量資料,紀錄應用程式的一些相關資訊。 ```java= private SharedPreferences sp; sp = this.getSharedPreferences("DATA", MODE_PRIVATE); // builder pattern 設計模式 回傳editor自己 // 寫入資料 sp.edit() .putString("DATA_NAME", "test") .putInt("DATA_AGE", 15) .commit(); // commit(直接同步寫入) or apply(找時機寫入) 才會將資料寫入 // 取資料(第2個參數是自己給的預設值) // 確保程式不會出錯,一定會有取到值 int i = sp.getInt("DATA_AGE", 0); ``` ### 多執行緒(Thread) 電腦來回切換正在處理的程序(process),做一點點後切換。 通常process死亡後,其下的thread都會跟著死亡。 :::info *為何網路連線都需要採用多執行緒?* 有網路不好的情況,若是只有單執行緒會造成程式直接卡死,會等待網路連線後才繼續執行程式。(UI會卡住) 需要採用多執行序分別負責網路連線以及UI控制的部分。 ::: ## 5/28(day62) ### BuilderPattern(建造者模式) 用來處理建構子無法滿足所有使用情況時。 * 創建相同實體的builder * 創建不同實體的builder ### Toast & AlertDialog Toast會彈出視窗,顯示文字訊息一段時間。 AlertDialog繼承自Dialog類別,用來彈出可選擇使用選項按鈕的視窗等, ### 誰是臥底?畫面實作 * seekBar * switch * AlertDialog.builder * LayoutInflator ## 5/29(day63) ### 頁面傳遞資訊 * Intent 傳遞值 * Bundle 打包成一包丟過去 * 序列化(sequentialable & parcelable) ### 改寫返回鍵 ### 實現雙擊螢幕做特定事件 利用延遲與boolean來實現。 拉出類別以及介面來實現: ```java= @Override public void onBackPressed(){ ClickedUtil.clicked(isClicked, new ClickedEventListener() { @Override public void singleClicked() { isClicked = true; Toast.makeText(MainActivity.this, "single clicked", Toast.LENGTH_SHORT).show(); new Handler().postDelayed(new Runnable() { @Override public void run() { isClicked = false; } }, 2000); } @Override public void doubleClicked() { Toast.makeText(MainActivity.this, "double clicked", Toast.LENGTH_SHORT).show(); MainActivity.super.onBackPressed(); } }); } ``` ```java= public interface ClickedEventListener { void singleClicked(); void doubleClicked(); } ``` ## 5/30(day64) * 誰是臥底?實作 ## 5/31(day65) * 誰是臥底?實作 ## 6/3(day66) * test14 ### RecyclerView ### Adapter Pattern ### Factory Pattern ## 6/4(day67) ### API ### GCP 環境建置 [GCP環境建置](https://hackmd.io/aBLvcH0HSHuD9HHUIXuzhg?both) ### Restful API * GET 運用網址來取得資料(一般不用於傳遞具隱秘性的資料) :::info https://www.google.com/search?safe=off&client=firefox-b-d&q=jiejie&spell=1&sa=X&ved=0ahUKEwjv4ra6oc_iAhUtGKYKHX0rDOQQBQgrKAA&biw=1244&bih=681 * 裡面可以看到有些safe、client...的變數名稱,表示是採用get的方式來做資料傳遞 ::: * POST * PUT * DELETE ### CRUD create、read、upload、delete ## 6/5(day68) * 自主練習 ## 6/6(day69) * 自主練習 ## 6/10(day70) * Test_15(RecyclerView & JSON應用) * 考試講解 ## 6/11(day71) ### Android 連結api * 連結"誰是臥底遊戲"? 採用"okhttp"此套件 [okhttp](https://github.com/square/okhttp) ### 網路連線功能封裝 ## 6/12(day72) ### 拆分專案架構(以node.js) ### GET & POST #### Get的方法 * params * query #### Post的方法 ### CallBack function [CallBack函式說明](http://fiend1120.pixnet.net/blog/post/196941375-callback-function) ## 6/13(day73) ### MongoDB建置 ## 6/14(day74) * 連接資料庫Api ## 6/17(day75) * 會員註冊系統api撰寫 ## 6/18(day76) * 會員註冊系統api撰寫 ## 6/19(day77) * 會員註冊系統api撰寫 * 誰是臥底檢查 ## 6/20(day78) * Vue環境建置 ## 6/21(day79) * 期末專題提案 ## 6/24(day80) * 會員註冊&登入系統作業檢查 * API test16 ## 6/25(day81) * 期末專題討論 ## 6/26(day82) * 期末專題討論 ## 6/27(day83) * 期末專題討論 ## 6/28(day84) * Trello * 專案開發技巧 看板方法 ## 7/1(day85) * 期末專題 ## 7/2(day86) * 加解密 * MD5 * RSA * SHA * JWT (JSON Web Token) ## 7/3(day87) ### Heap Sort * heap sort 一般使用場景 外部排序 ## 7/4(day88) * 期末專題 ## 7/5(day89) * 期末專題 ## 7/8(day90) * 期末專題 ## 7/9(day91) ### 設計模式-觀察者模式 ### 設計模式-狀態模式 ### And Or 邏輯閘實現 ## 7/10(day92) * 期末專題 ## 7/11(day93) * 期末專題 ## 7/12(day94) * 期末專題 ## 7/15(day95) * 期末專題 ## 7/16(day96) * 期末專題 ## 7/17(day97) * 期末專題 ## 7/18(day98) * 期末專題 ## 7/19(day99) * 期末專題 ## 7/22 ~ 7/26(day100 ~ day104) * 期末專題 ## 7/29 ~ 8/2(day105 ~ day109) * 期末專題 ## 8/5 ~ 8/8(day110 ~ day113) * 期末專題&期末發表彩排 ## 8/9(day114) * 颱風假 ## 8/13(day115) * 期末發表&結業式 ## 8/14(day116) * 公司企業參訪(全曜、上詠、錢管家、金尉、超級物種、MDBS) ## 8/15(day117) * CMoney筆試 ###### tags: `java`