## JVM and JDK and JRE 1. JVM(虛擬機)是模擬出來的,沒有實體。解決差異化,不需因電腦差異重複編寫程式 2. Jre 是java runtime environment, 是java程序的運行環境。包含jvm虛擬機,還有所有java類庫的class文件,都在lib目錄下打包成了jar。 3. Jdk 是java development kit,是java的開發工具包,裡面包含了各種類庫和工具,代碼(檔名.java)+編譯(javac)+字節碼(檔名.class<在IDEA會放在out資料夾>)+JVM(java.exe)包含經常使用的指令與編譯器包含JRE ## Eclipse EE and Tomcat 安裝 1. 下載 Eclipse EE + JDK 8 + Tomcat 9 2. 根據只是解壓縮並安裝 3. 打開Eclipse 4. 選擇專案所放置的根路徑 5. 左上角點選Windows > Server > Runtime Environment > Add 把 Tomcat加進來 6. 選擇Tomcat版本 7. 點擊創建本地伺服器 8. 根據安裝的Tomcat去找路徑 9. 點擊finish就ok了 10. File -> New -> Dynamic Web Project 11. Project names > helloworld 12. src右鍵new新增index.jsp,在body中輸入helloworld 13. 右鍵點擊專案 run as > run on server 14. 選擇manually define a new server,並選擇剛才add的tomcat然後finish 15. 跳出一個預設的broswer, 裡面顯示Hello World成功了 16. 可以在下面視窗 Servers 的Tomcat 上按右鍵Stop 17. https://progressbar.tw/posts/2 18. http://blog.appx.tw/2017/04/27/java-web-app-eclipse-tomcat/ ### 安裝問題 1. Eclipse - "Incompatible JVM. Version 1.8.0_261 of the JVM is not suitable for this product. Version: 11 or greater is required" -> **https://stackoverflow.com/questions/63996047/eclipse-incompatible-jvm-version-1-8-0-261-of-the-jvm-is-not-suitable-for-th** 2. Unknown version of Tomcat was specified. -> **下載完tomcat後要開一次檔案eclipse才能讀取到資料夾** 3. The server cannot started because one or more of the ports are invalid -> **下方server右鍵點開open,右方的tomcat admin port改成數字而非-,存檔重新run on server** ## Java基礎 ### 選擇 ```java= //if-else public class Demo{ public static void main(String[] args){ System.out.println(); if(3 > 5){ System.out.println("3 is larger than 5"); } else if(4 > 5){ System.out.println("4 is larger than 5"); } else if(5 > 5){ System.out.println("5 is larger than 5"); } else if(6 > 5){ System.out.println("6 is larger than 5"); } else{ System.out.println("no match result"); } System.out.println(); } } //result = 6 is larger than 5 //switch public class Demo{ public static void main(String[] args){ System.out.println(); switch(6){ case 3: System.out.println("you choose 3.."); break; case 4: System.out.println("you choose 4.."); break; case 5: System.out.println("you choose 5.."); break; case 6: System.out.println("you choose 6.."); break; default: System.out.println("no match result"); } System.out.println(); } } //result = you choose 6.. ``` ### 迴圈 ```java= // while loop public class Demo{ public static void main(String[] args){ int i = 10; while i > 0; System.out.println(i); i--; } } //result = 10 9 8 7 6 5 4 3 2 1 //while 迴圈有一種變形,就是加上關鍵字 do 變成 do-while 迴圈,這是前測試迴圈,形式如下 do { statement(s) }while (expression); //也就是說, do-while 迴圈至少會進行迴圈的第一次工作,然後才進行結束條件測試。 //若是迴圈沒有明確重複次數,那就得另行設計結束迴圈的方式,例如控制變數等於某一個值之時,再利用 break 跳出迴圈。 // for loop public class Dem{ public static void main(String[] args){ for(int i = 10; i > 0; i--){ System.out.println(i); } } //result = 10 9 8 7 6 5 4 3 2 1 // foreach 迴圈可以用來依序取得複合資料型態物件中的所有元素 public class Demo{ public static void main(String[] args){ int[] a = new int[10]; int v = 10; for(int i = 0; i < 10; i++){ a[i] = v--; } for(int i : a){ System.out.println(i); } } } //result = 10 9 8 7 6 5 4 3 2 1 ``` ### 關鍵字 * ***public***可用在: 1. class前面表示此class可以供其他package裡的類別使用。同一個目錄下的class均可視為屬於同一個package。 2. object or class member前面, 表示所有的class均可存取此member。 * ***private***可用在object or class member前面, 表示只有定義這些member的class才可存取。 * ***static***可用在member前面。如果member前面有static, 表示該member屬於class,否則屬於object。不論系統創造了多少object,class variable只有一個;而每個object都有其object variable。存取class method的語法是ClassName.classMethod();存取object method時,則必須以reference.objectMethod()來呼叫。在Object Method裡,可用this表示目前的物件。但在Class Method裡就不能存取object member了。 * ***this***表示目前這個物件 * ***String***定義於java.lang package下面的類別, 屬於Java語言定義的標準程式庫。 * ***System***定義於java.lang package下面的類別, 屬於Java語言定義的標準程式庫。 * ***System.out***是class System裡面的一個Class Variable, 其型態為reference to 定義於java.io package裡面的PrintStream。我們可透過該變數所指到的物件, 將訊息印到螢幕上。 * ***System.gc***是class System裡面的一個Class Method, 呼叫該方法可強迫JVM回收沒有被任何reference指到的物件。當物件被回收時, 該物件的finalize方法會被呼叫。 * ***new***用來產生新的物件。後面必須跟著某個constructor, 以便進行初始化的動作。 * ***void***是一個關鍵字,用於表示一個方法(函數)不返回任何值。當你定義一個方法為 void 型別時,表示該方法執行一些操作或運算,但不會返回任何結果。 ### 類別與物件 class就是類別,類別裡面可以定義屬性和方法,屬性就是專屬於類別的變數 (variable),方法則是類別進行工作的地方。如果這個類別還需要是可執行的,就得額外定義特別的 main() 方法 ```java= package classdemo01; // 宣告類別名稱 public class ClassDemo01 { // 這裡定義屬性 int a; // 這裡定義方法 public int doSomething(int p1) { return a + p1; } // 這裡定義 main() 方法 public static void main(String[] args) { ClassDemo01 d = new ClassDemo01(); d.a = 11; System.out.println(); System.out.println(d.doSomething(5)); System.out.println(); } } //result = 16 ``` 屬性及方法合稱成員: 1.沒有static -> 屬於object,如實體屬性(int a)、實體方法(dosomething) 2.有static ->該member屬於class,如類別方法(main) 實體和類別不能互相存取,如果要在 main() 中使用 a ,那就得在 main() 裡建立 ClassDemo01 型態的物件實體。 此例在 main() 中建立 ClassDemo01 的實體變數 d ,然後將 d 的屬性 a 設置為 11 然後呼叫 doSomething() 方法 接著我們往上找實體屬性 a 的宣告 通常屬性的宣告會放在 class 關鍵字 (keyword) 的下一行,數量依需求而定。 https://medium.com/ai%E5%8F%8D%E6%96%97%E5%9F%8E/%E9%A1%9E%E5%88%A5-class-%E7%89%A9%E4%BB%B6-object-%E5%92%8C%E5%AF%A6%E9%AB%94-instance%E7%9A%84%E5%B7%AE%E5%88%A5-%E8%BD%89%E9%8C%84-5f359c9787fd ### 多載(overload) Java 允許方法可以有不同的參數列版本,這稱之為多載 (overload) ,我們將 ClassDemo01 的 doSomething() 改成多載版本,如下 ```java= package classdemo02; public class ClassDemo02 { int a; // 這裡定義 doSomething() 的第一個版本 public int doSomething(int p1) { return a + p1; } // 這裡定義 doSomething() 的第二個版本 public double doSomething(double p1) { return a + p1; } public static void main(String[] args) { ClassDemo02 d = new ClassDemo02(); d.a = 11; System.out.println(); System.out.println(d.doSomething(5)); System.out.println(d.doSomething(7.2)); System.out.println(); } } //result = 16 18.2 ``` 回傳值型態 (return type) 並不影響多載的版本差異,只有參數列不同才構成多載,至於參數列指參數的型態、數量、排列順序等。 如果運算式中的兩個數值 (value) 都是基本資料型態 (primitive data type) ,編譯器 (compiler) 會自動替其中一個數值先進行型態轉換,如上面第二個 doSomething() 的 a + p1 的 a 會先轉換成 double ,然後才與 p1 相加。 ### 封裝 封裝的意思就是把屬性封在類別中,這還牽涉到程式設計中另一個重要的概念-資訊隱藏 (information hiding)。主要就是不讓外界隨意存取類別的屬性,也就是說,只讓類別的屬性給同個類別的方法存取。 當屬性宣告為 private 的時候,該屬性就只能由同一個類別存取,我們將 Demo 類別的屬性 a 封裝,改寫成 Demo01 類別,程式如下 ```java= package Demo; public class Demo{ //首先,屬性宣告為 private ,這樣屬性就只限類別 中可存取 private int a; // 接著如果要讓外界可以存取已封裝的屬性,就要另外設置 public 的 getter 與 setter 方法 //setter public void setA(int p1){ a = p1; } //getter public int getA(){ return a; } public intdoSomething(int p1){ return a + p1; } public static void main(String[] args) { Demo d = new Demo(); // 利用 setter 設定屬性 d.setA(11); System.out.println(); // 利用 getter 印出屬性 a System.out.println(d.getA()); System.out.println(d.doSomething(1)); System.out.println(); } } //result = 11 12 ``` **private**:只有A自己才可以存取, 使用keyword private **package**:只有和A同一個package的class才可以存取, 沒有相對應的keyword **protected**:只有同一個package或是A的子類別才可以存取, 使用keyword protected **public**:所有的class都可以存取, 使用keyword public 如果member的前面沒有private,protected,public其中一個修飾字,則該member的存取範圍就是package。從以上的敘述,public > protected > package > private。 ### package Package的定義 所謂package,可以想成是在設計或實作上相關的一群class。要宣告某class屬於某package,其語法為 ```java= package myPackage; public class MyClass { } // 如果沒有宣告package的話,如下面這兩個class,就會被歸類為「匿名」的package: // in file ClassA.java public class ClassA { public static void main(String[] argv) { ClassB x = new ClassB(); } } // in file ClassB.java public class ClassB { } //Class A用到package myPackage裡的Class B,引入的語法為 import myPackage.B; //引用相當多個同屬某package的類別,Java允許我們使用萬用字元*來代表某package裡的所有class import myPackage.*; public class A { public static void main(String[] argv) { B x = new B(); } } ``` ### 建構子 如果我們想要建立物件的同時設定好屬性,就需要自訂建構子 (constructor) ,所謂建構子是一種特別的方法 (method) ,特別的地方是在建構子是建立物件 (object) 時所執行的方法。 ```java= package classdemo04; //此例 ClassDemo04() 有一個 int 參數 (parameter) p1 ,然後直接以 p1 設定屬性 (field) a 。注意建構子沒有回傳值 (return value) ,這是因為建構子就是用來建立物件,因此預設回傳物件本身。 public class ClassDemo04 { private int a; // 這裡定義建構子 public ClassDemo04(int p1) { setA(p1); } public void setA(int p1) { a = p1; } public int getA() { return a; } public int doSomething(int p1) { return a + p1; } public static void main(String[] args) { //由於建構子有參數,因此呼叫建構子建立物件時也需要提供參數 ClassDemo04 d = new ClassDemo04(12); System.out.println(); System.out.println(d.getA()); System.out.println(d.doSomething(1)); System.out.println(); } } //result = 12 13 ``` ### this 下面我們介紹個小技巧,建構子或方法的參數識別字 (identifier) 也可以跟屬性一樣,這時候存取屬性就要利用 this 關鍵字了,我們將 ClassDemo04 改成用 this 存取屬性,如下 ```java= package classdemo05; public class ClassDemo05 { private int a; public ClassDemo05(int a) { setA(a); } public void setA(int a) { // 利用 this 存取屬性 this.a = a; } public int getA() { return a; } public int doSomething(int a) { // 參數跟屬性使用相同的識別字 return this.a + a; } public static void main(String[] args) { ClassDemo05 d = new ClassDemo05(13); System.out.println(); System.out.println(d.getA()); System.out.println(d.doSomething(9)); System.out.println(); } } //result = 12 13 ``` ### 繼承 繼承的寫法是在類別名稱用關鍵字 extends ,之後再接所繼承的類別名稱,例如 ```java= public class Elephant extends Animal ``` 這樣 Elephant 類別就繼承了 Animal 類別。以下為 Animal 類別的完整程式碼 ```java= package classdemo06; public class Animal { //這裡 protected 的屬性可以被子類別繼承, private 則不行。 protected String name; //建構子可以多載,方法 (method) 也可以多載 public Animal() { this.name = "動物"; } public Animal(String s) { this.name = s; } // public 存取上完全沒有限制都會被子類別繼承 public void speak() { System.out.println("哈囉,我是" + this.name); } } ``` 以下是子類別 Elephant ```ja= package classdemo06; public class Elephant extends Animal { public Elephant() { this.name = "大象"; } } ``` 另一個子類別 Mouse ```java= package classdemo06; public class Mouse extends Animal { public Mouse() { this.name = "老鼠"; } } ``` Elephant 及 Mouse 都繼承自 Animal ,這裡只有定義兩者各自的建構子, Elephant() 將 name 設定為 "大象" , Mouse() 則是設定為 "老鼠" 。 然後執行部分放在 ClassDemo06 類別 ```java= package classdemo06; //關鍵字 import 用來引入 Java API 中的類別,這裡 ArrayList 與 List 是在 java.util 之中,如果類別是在 java.lang ,例如 String 類別就不需要使用關鍵字 import 引入。 import java.util.ArrayList; import java.util.List; public class ClassDemo06 { public static void main(String[] args) { //這裡 animal_list 是 List 型態, List 是 ArrayList 實作的介面, List 之後用角括弧圍住 Animal 型態名稱,這是設定 List 裡頭的元素必須是 Animal 或 Animal 的子類別。 //等號右邊用關鍵字 new 建立 ArrayList 型態的物件,由於 ArrayList 實作 List 介面,因此 ArrayList 屬於 List 型態,這裡 ArrayList 後面也是用 角括弧圍住 Animal 型態名稱,表示 animal_list 包含的是 Animal 型態的物件。 //ArrayList 是類似陣列 (array) 的資料型態,相較陣列有更多好用的方法。 List<Animal> animal_list = new ArrayList<Animal>(); //繼續用 add() 方法將 Animal 、 Elephant 、 Mouse 等物件加入 animal_list animal_list.add(new Animal()); animal_list.add(new Elephant()); animal_list.add(new Mouse()); //最後用 for 迴圈呼叫每一個物件的 speak() 方法 //這裡就用到了多型的觀念,由於 Elephant 跟 Mouse 兩個類別都繼承自 Animal 類別,因此在使用像是 ArrayList 的時候,就可以在宣告時用 Animal 替代 Elephant 或 Mouse 。 for (Animal item:animal_list) { item.speak(); } } } //result = 哈囉,我是動物 哈囉,我是大象 哈囉,我是老鼠 ``` ### 介面 定義介面 (interface) 使用關鍵字 interface ,套件 (package) 則用關鍵字 package。類別 (class) 除了可以繼承 (inheritance) 之外,也可以實作介面,介面基本上是宣告成員 (member) ,例如屬性 (field) 跟方法 (method) ,但是不實作方法內容,例如 ```java= //shape 宣告常數 PI 與兩個方法 interface shape { public double PI = 3.14; //getPerimeter() 用來計算周長 public double getPerimeter(); //getArea() 計算面積 public double getArea(); } //類別如果要實作介面使用關鍵字 implements ,例如實作以上的 shape public class CircleDemo implements shape //這樣 CircleDemo 就必須實作 shape 中的 getPerimeter() 與 getArea() 。 package circledemo; interface shape { public double PI = 3.14; public double getPerimeter(); public double getArea(); } public class CircleDemo implements shape { private double radius; public CircleDemo(double radius) { this.radius = radius; } public double getPerimeter() { return 2 * this.radius * this.PI; } public double getArea() { return this.PI * this.radius * this.radius; } public static void main(String[] args) { CircleDemo demo = new CircleDemo(100.1); System.out.println(); System.out.println(demo.getPerimeter()); System.out.println(demo.getArea()); System.out.println(); } } //result = 628.628 31462.8314 ``` ### static 這是說類別在程式執行時就已存在,如果程式中有用 new 及建構子 (constructor) 建立物件,才會有物件存在,所以物件又被稱為實體 (instance) 。有static宣告都是類別;反之都是物件。 static 方法 (method) 可以存取 static 屬性 (field) 若要使用非 static 屬性或呼叫非 static 方法就得建立物件實體,使用main()。 static 方法也稱為類別方法 (class method) ,同樣 static 屬性也稱為類別屬性 (class attribute) 。 至於存取 static 屬性或 static 方法則用類別名稱即可,舉例如下 ```java= package staticdemo; public class StaticDemo { //屬性 a 宣告為 static , static 屬性可以直接指派初值 private static int a = 0; private int b; //方法 test() 也宣告為 static public StaticDemo() { a++; b = 0; } //由於 Java 為強型態的程式語言 (programming language) ,所謂強型態除了要宣告 (declare) 型態 (type) 外,計算結果也都得符合所宣告的型態,此例的 test() 需要回傳 double ,這裡的小括弧加上 double 就是強制將 a/10 的計算結果轉換成 double 。 public static double test() { return ((double) a / 10); } public static void main(String[] args) { for (int i = 0; i < 10; i++) { StaticDemo d = new StaticDemo(); System.out.println(); //下方存取 a 或呼叫 test() 都是用類別名稱 int p1 = StaticDemo.a; System.out.println(p1); System.out.println(d.b); double p2 = StaticDemo.test(); System.out.println(p2); System.out.println(); } } } // result = 1 0 0.1 2 0 0.2 3 0 0.3 4 0 0.4 5 0 0.5 6 0 0.6 7 0 0.7 8 0 0.8 9 0 0.9 10 0 1.0 ``` **https://blog.kenyang.net/2011/03/09/java-staticfinal** ## 8/24 簡報 rest api舉例 狀態碼舉例