# 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);
}
}
```