# java 課程筆記 ## 基本介紹 - 特性:物件導向 - 優點:可以跨平台,安全性高,開發資源與環境齊全 - 缺點:速度慢,編譯麻煩 - 應用性:android軟體,網站,物聯網 # 語法 ## 基本概念 ### 專案結構 java專案下面會有 - 專案 - src 程式碼 - App.java - Fabonacii.java - bin 編譯後的文件 - lib 函式庫 然後src中的每一個文件都是一個java文件,並且每一個文件裡面都有一個必須包含一個class(且只能有一個) --- ### 程式碼結構 ```java package 最外層包; import 函式庫; class 類名{ 函式和程式碼(一定要包含主函式main) } ``` --- ### 每一行的結束 ```java import java.util.Scanner; ``` 每一行都需要用分號做結尾(不然你就會看到它瘋狂報錯) --- ### 程式碼註釋 ```java //我是單行註釋 /* 我是多行註釋 我也是多行註釋 */ ``` --- ### 變數的宣告Declaration java中的內建資料結構的宣告同樣是<mark>限定記憶體大小</mark>的,但是如果是物件的宣告就不會限制 ```java int a;//宣告一個整數變數,但不賦值 int b=0;//宣告一個整數變數,並設定其值為0 float c=0.005;//宣告一個浮點數(單精度),並設定其值為0.005 String d="s1231"; char e='g'; boolean f=true; ``` 每一行都需要用分號做結尾(不然你就會看到它瘋狂報錯) #### 修飾字: 放在宣告的最前面 ```java private//同class內可見 protected//同class內及其子類別可見 public//所有都可見 static//獨立於類別 final//不能被重新賦值,類似常數 //舉例 private int a=0; ``` --- ### 運算子 ```java +、-、*、/、%(mod)、=(賦值)、== ``` --- ### 判斷語句 小括號裡面就是條件判斷式,且只有該條件判斷式的結果是true的時候才會執行大括號的內容 ```java if(條件){ //執行的東東 }else if(條件){ //執行的東東 }else{ //執行的東東 } ``` --- ### 循環 - while循環 ```java while(條件){ //執行的東東 } ``` - for循環 ```java //掛號裡面(索引變數的起始值,循環條件,迭代運算) for(int i=0;i<10;i++){ //執行的東東 } ``` --- ## 基本輸入輸出 ```java= import 必要函式庫; package 最外層結構; public class App{ public static void main(String[] args) throws Exception{ System.out.print("Hello, world!"); } } ``` 必須包含一個class,然後執行的時候就會去<mark>src目錄下</mark>去找main函式所在的位置並執行main, --- ### 輸出: 在java中要輸出內容到<mark>終端機</mark>,可以直接使用進行輸出 ```java System.out.print();//單純輸出內容(不換行) System.out.println();//輸出後自動換行(相當於接一個\n) ``` --- ### 從鍵盤輸入: 在java中是使用Scanner物件進行讀取,所以需要先import該物件 ```java import java.util.Scanner; ``` 然後再在main函式中用系統輸入流作為參數,建立一個物件的實體(有點類似c++和javascript的合體) ```java Scanner scanner=new Scanner(System.in); ``` 再之後就可以直接針對建立的這個`Scanner`實體進行使用(通過物件的方法),<mark>常見的方法</mark>(method): * `nextInt();` 從鍵盤輸入的整數 * `nextDouble();` 從鍵盤輸入的浮點數(雙精度) * `nextLine();` 從鍵盤輸入的一行(字串) * `nextFloat();` 從鍵盤輸入的浮點數(單精度) 完整程式: ```java= //從鍵盤讀取一個整數,並輸出 import java.util.Scanner; public class App{ public static void main(String[] args) throws Exception { Scanner scanner=new Scanner(System.in); int a=scanner.nextInt(); System.out.print(a); } } ``` --- ## 函式 用於重複使用一段程式,或者重複利用某一個功能,那使用函式分為兩個部分: 1. 宣告函式 2. 呼叫函式 宣告函式(基本上都要在class裡面宣告) ```java 修飾字 返回值類型 函數名稱(參數){ //程式 return 1; } ``` 呼叫函式 ```java 函數名稱(參數); ``` ### 範例:(費氏數列) ```java= private static int Fabonacii(int a){ if(a==0) return 0; if(a==1) return 1; return Fabonacii(a-1)+Fabonacii(a-2); } //main裡面的呼叫 System.out.print(Fabonacii(10)); ``` --- ## 類class class主要的作用<mark>分為兩種</mark>,<mark>一種是單純裝載函式</mark>,<mark>另一種就是物件的模板</mark>,通過一個統一的模板,建立<mark>不同</mark>的實體物件(類似前面的`Scanner`),而這個物件中可以包含很多的`屬性`和`方法`。 之前有提到每一個java的程式碼檔案(`.java`)都只能包含一個class,所以如果想要使用class基本上就要在`src`目錄之下建立一個新的檔案 ### 單純裝載函式 這樣做的目的主要就是<mark>模塊化原始碼</mark>,將程式中負責不同功能的區塊分開(中主程式中分離),並且在java中同一個目錄下(就是都在src)的檔案<mark>可以不用import就直接使用</mark>,所以在主程式中要使用該函式只要`christmassTree.christmas_tree(10);`就可以呼叫到位於`christmasTree`這個類之下的函式 ```java= public class christmasTree { public static void christmas_tree(int a) throws Exception { for(int i=0;i<=a;i++){ for(int k=0;k<=a-i;k++) System.out.print(" "); for(int j=0;j<i*2-1;j++){ System.out.print("*"); } System.out.println(); } } } ``` ### 物件模板(封裝) class可以作為物件的模板,並且<mark>以次模板產生的多個相互獨立的物件</mark>(不會互相影響)。就很像是有一個叫“人類”的class,然後用這個class創建出了“馬斯克”和“郭台銘”,他們都具備一些<mark>屬性</mark>(像是身高、錢、體重...),並且都可以<mark>做一些事情</mark>(物件的方法),比如買房子,貸款。 #### 物件的屬性: 其實就是<mark>裝在物件之下</mark>的一個“變數” ```java 物件.屬性 ``` #### 物件的方法: 其實就是<mark>裝在物件之下</mark>的一個“函式” ```java 物件.方法() ``` #### 定義模板: ```java= //Student.java檔案 public class Student{ //宣告物件屬性 private int height; private int weight; private int score; private String name; //物件初始化函式(建立物件的時候自動執行) public Student(String input_name,int height,int weight,int score){ this.height=height; this.weight=weight; this.score=score; this.name=input_name; } //物件方法 public int get_score(){ return this.score; } public void set_score(int score){ this.score=score; } } ``` ```java= //App.java檔案 public class App{ public static void main(String []args)throws Exception{ Student student_1=new Student("王小明",170,70,59);//建立一個student_1的實體物件,並且帶有資料 System.out.println(student_1.get_score()); } } ``` 在上述範例中包含幾個部分:<mark>宣告物件屬性</mark>、<mark>初始化函式</mark>和<mark>物件方法</mark>。 第一段的4~7行宣告了Student這個class中具備的屬性,(身高,體重,分數和名字)。 然後要建立物件模板的class基本上不可缺少的就是與class<mark>同名的函式</mark>,而這個函式的目的就是針對建立的物件進行初始化。 #### 物件實體的建立: ```java 類別名 實體名稱 = new 類別名(初始化參數); Student student_1=new Student("王小明",170,70,59); ``` 這邊通過class模板建立物件實體的方法其實跟c++中很類似。 #### 封裝:(對原始資料進行隔離) 其實可以注意到,在上面的例子之中,我有可以的把Student的幾個屬性的存取權限都設定為<mark>private</mark>,也就是<mark>只有在同一個class中才能存取</mark>,而這也可以保證變數的安全性(保護原始資料的安全性),而我們可以將所有需要對物件屬性進行的操作封裝,讓使用者只能通過設計好的物件方法(method)獲取,或者變更。 --- # 範例 ## 生成n行的雪花樹(需要搭配一個main函式) ```java= public class christmasTree { public static void christmas_tree(int a) throws Exception { for(int i=0;i<=a;i++){ for(int k=0;k<=a-i;k++) System.out.print(" "); for(int j=0;j<i*2-1;j++){ System.out.print("*"); } System.out.println(); } } } ``` ## 費氏數列(App.java) ```java= import java.lang.Math; import java.util.Scanner; public class App { public static void main(String[] args) throws Exception { Scanner scanner=new Scanner(System.in); int a=scanner.nextInt(); // double b=scanner.nextDouble(); // System.out.println(Math.round(a*100.0)/100.0); System.out.println(Fabonacii(a)); // System.out.println(scanner.nextDouble()); } private static int Fabonacii(int a){ if(a==0) return 0; if(a==1) return 1; return Fabonacii(a-1)+Fabonacii(a-2); } } ``` ## 成績判斷(App.java) ```java= import java.util.Scanner; public class App { public static void main(String[] args) throws Exception { Scanner scanner=new Scanner(System.in); double input_double=scanner.nextDouble(); if(input_double>=90){ System.out.println("A+"); }else if(input_double>=80){ System.out.println("A"); }else if(input_double>=70){ System.out.println("B"); }else if(input_double>=60){ System.out.println("C"); }else{ System.out.println("F"); } } } ``` # FRC的java 主要使用WPILIB,對vscode進行擴展 ## FRC專案結構 - .gradle - .vscode - .wpilib - build - gradle - src <mark>程式碼</mark> - main - deploy - java - frc - robot - Main.java <mark>java中必須的main函式所在</mark> - Robot.java <mark>主要程式碼</mark> - vendordeps <mark>主要跟函式庫有關</mark> 因為frc一樣是在java的環境之下運作,所以還是要具備main函式,只是在main中再呼叫Robot檔案(所以實際的運作還是再Robot檔案) ## Robot.java的結構 ```java package frc.robot; import com.kauailabs.navx.frc.AHRS; import edu.wpi.first.wpilibj.Joystick;//搖桿 import edu.wpi.first.wpilibj.PWMVictorSPX;//馬達控制器 import edu.wpi.first.wpilibj.TimedRobot; import edu.wpi.first.wpilibj.Timer;//計時 import edu.wpi.first.wpilibj.SPI;//SPI介面 import edu.wpi.first.wpilibj.drive.DifferentialDrive; public class Robot extends TimedRobot{ @Override public void robotInit() { } //自動化的初始化 @Override public void autonomousInit() { } @Override public void autonomousPeriodic() { } //手動控制 //手動控制的初始化 @Override public void teleopInit() { } //手動控制的loop @Override public void teleopPeriodic() { } } ``` 最主要的還是Robot這個class中的函式, 函式中主要會包含 - 總初始化 - 自動化時間 - 自動化時間的初始化 - 自動化時間的loop - 手動化時間 - 手動化時間的初始化 - 手動化時間的loop 因為frc的比賽規定中有規定,在開始的時候會有<mark>15秒鐘的自動化執行</mark>,然後之後的時間就會是<mark>手動操作</mark>,而在自動化時間中也可以結合很多的東西(像是computer vision電腦視覺,話說電腦電腦視覺的部分可以使用<mark>grip</mark>和<mark>limelight</mark>這些工具通過拉方塊的方式生成對應的程式) ## Robot.java範例 大部分的內容其實可以查WPILIB的java api ```java package frc.robot; import com.kauailabs.navx.frc.AHRS; import edu.wpi.first.wpilibj.Joystick;//搖桿 import edu.wpi.first.wpilibj.PWMVictorSPX;//馬達控制器 import edu.wpi.first.wpilibj.TimedRobot; import edu.wpi.first.wpilibj.Timer;//計時 import edu.wpi.first.wpilibj.SPI;//SPI介面 import edu.wpi.first.wpilibj.drive.DifferentialDrive; public class Robot extends TimedRobot{ @Override public void robotInit() {} //自動化的初始化 @Override public void autonomousInit() { m_timer.reset(); m_timer.start(); gyro.enableLogging(true); gyro.calibrate(); gyro.reset(); } @Override public void autonomousPeriodic() { // Drive for 2 seconds if (m_timer.get() < 2.0) { double err=gyro.getYaw(); m_robotDrive.tankDrive(0.5+err*0.03,0.5-err*0.03); } else { m_robotDrive.stopMotor(); // stop robot } } } //手動控制 //手動控制的初始化 @Override public void teleopInit() {} //手動控制的loop @Override public void teleopPeriodic() { m_robotDrive.arcadeDrive(m_stick.getY(), m_stick.getX()); if(m_stick.getRawButton(1)) { intake1.set(0.8); intake2.set(-0.8); }else if(m_stick.getRawButton(2)){ intake1.set(-0.8); intake2.set(0.8); }else{ intake1.set(0); intake2.set(0); } } ```