## 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舉例
狀態碼舉例