南昌航空大學-軟體學院-22207107-胡優樂-JAVA第一次Blog作業
前言
距離開學第一次接觸java已然過去了將近兩個月時間,在這段時間裡我們總共進行了三次大作業聯絡,基於這三次大作業的體量及設計的知識點,難度分佈,我做了以下的總結:
1.第一次大作業總共有五題,分別是:1.設計一個風扇的類,2.類和物件的使用,3.成績設計1-類,陣列的基本運用,4.成績設計2-關聯類,5.答題程式1。實際做下來的體會是:
(1)第一題難度入門級別,涉及的知識點是設計類,建立該類的物件並輸出其狀態,常量定義,私有成員變數,toString等。
(2)第二題難度入門級別,涉及到的知識點是建立一個簡單的學生類,並透過構造器、訪問器、修改器和重寫 toString 方法來處理學生的屬性。
(3)第三題難度為基礎,涉及的知識點是物件導向程式設計:使用類和物件封裝學生的資訊及行為;構造方法用於執行特定功能的函式,計算總分、平均分;使用陣列儲存多個學生物件;將輸入行分隔為多個部分,方便提取資料。
(4)第四題難度難度為基礎,涉及的知識點主要是關聯類,建立一個 Course 類來表示課程的資訊和成績,然後將其與 Student 類關聯。
(5)第五題難度為困難,涉及到的知識點主要是定義多個類,每個類負責特定的功能,方法的定義和使用(新增題目,儲存答案等)以及資料結構(HashMap和Array List)允許高效的查詢和插入,正規表示式的基本運用。
2.第二次大作業共有五道題:
第一題 手機按價格排序、查詢,難度:一般。涉及的知識點主要是:Comparable介面;Collections.sort(phoneList)對phoneList中的手機物件進行排序;
第二題 sdut-oop-4-求圓的面積(類與物件)難度:簡單。涉及的知識點:類和物件,有參無參方法構造,方法,呼叫方法。
第三題 汽車類 難度:入門。涉及的知識:類和物件,方法。透過在Main類中建立Car物件(例如Car car = new Car("bob", 0.0f, 0.0f);),我們可以對汽車進行操作。
第四題 答題程式2 難度:困難。答題程式2相較於1增加了試卷資訊,涉及的知識:正規表示式,
2.第三次大作業共有三道題:
第一題 物件導向程式設計(封裝性) 難度:簡單。 涉及的知識: 類和物件;成員變數私有化;構造方法;訪問器修改器;資料驗證。
第二題 jmu-java-日期類的基本使用 難度:簡單。涉及的知識:LocalDate;ChronoUnit;判斷閏年;LocalDate.parse() 方法來嘗試將字串解析為日期;使用 split(" ") 方法將輸入的日期範圍字串分割成開始日期和結束日期。
第三題 答題程式三 難度:困難。涉及的知識:
設計與分析
1.答題判題程式1
設計實現答題程式,模擬一個小型的測試,要求輸入題目資訊和答題資訊,根據輸入題目資訊中的標準答案判斷答題的結果。
1. 類的設計
1.1 Matter 類
功能: 封裝單個題目的資訊,包括題號、題乾和正確答案。提供了獲取這些資訊的方法以及用來判斷使用者答案是否正確的功能。
成員變數:
id: 題號
idcontent: 題幹
ZQAnswer: 正確答案
方法:
構造器用於初始化題目資訊。
judgeAnswer(String answer): 用於驗證給定答案與標準答案是否一致。
public boolean judgeAnswer(String answer) {
return ZQAnswer.trim().equals(answer.trim());
}
1.2 testPaper 類
功能: 封裝整張試卷的資訊(題目沒有規定多張試卷預設一張試卷),包含題目集合和題目數量的統計。提供了新增題目和獲取題目的方法。
成員變數:
private HashMap<Integer, Matter> matters;
private int nums;
matters: 儲存題目的 HashMap,以題號為鍵,題目為值。
number: 題目的數量。
方法:
addMatter(Matter item): 新增題目。
getMatter(int id): 獲取指定題號的題目。
getMatterCount(): 獲取題目總數。
1.3 Responsepaper 類
功能: 封裝使用者的答卷資訊,包括試卷和使用者的答案。提供了儲存答案、驗證答案以及輸出結果的功能。
成員變數:
exam: 關聯的試卷,型別為 testPaper 的物件,表示當前與之關聯的試卷。這使得 Responsepaper 可以訪問試卷中的題目及其正確答案
answers: 儲存使用者答案的列表。
results: 儲存答題結果(正確與否)的列表。
方法:
savedaan(String daan): 記錄使用者的答案。
judgeAnswers(): 驗證所有答案的正確性並儲存結果。
public void judgeAnswers() {
for (int i = 0; i < answers.size(); i++) {
Matter matter = exam.getMatter(i + 1); // 假設題號從1開始
if (matter != null) {
boolean result = matter.judgeAnswer(answers.get(i));
results.add(result);
} else {
results.add(false); // 對於不存在的題目,記錄為錯誤
}
}
}
這個方法遍歷使用者的答案列表,將每個答案與對應的題目進行比對。透過呼叫試卷中的 getMatter() 方法獲取對應題目,然後呼叫題目的 judgeAnswer() 方法進行判斷,並將結果新增到 results 列表中。
putresults(): 列印使用者的答案和判題結果。
1.4主類
功能:題目輸入(迴圈控制,讀取一行使用者的輸入,字串處理,提取題號,提取題目內容,提取題目答案,建立Matter物件並新增到題庫中。)
for (int i = 0; i < Counts; i++) {
String x = scanner.nextLine().trim();
String[] nums = x.split("#");
int number = Integer.parseInt(nums[1].split(":")[1].strip());
String content = nums[2].split(":")[1].strip();
String answer = nums[3].split(":")[1].strip();
paper.addMatter(new Matter(number, content, answer));
}
輸入作答(建立物件,讀取使用者輸入答案直到輸入end,處理字串,遍歷答案,檢查格式,儲存到物件中)
Responsepaper responsepaper = new Responsepaper(paper);
String inputAnswer;
while (!(inputAnswer = scanner.nextLine().trim()).equals("end")) {
String[] answers = inputAnswer.split("#");
for (String ans : answers) {
if (ans.startsWith("A:")) {
responsepaper.savedaan(ans.split(":")[1].strip());
}
}
}
透過呼叫 judgeAnswers() 方法來對使用者的答案進行評判,並呼叫 putresults() 方法輸出判題結果。
類圖:
``
順序圖:
2.答題判題程式2
答題判題程式2相比於1的難度增加了不少,加上我開始的時間玩,最後只得了36分,很是可惜,事後我又認真地分析了這次題目,它在答題程式2的基礎上增加了試卷的資訊,並且題目資訊、試卷資訊和答題資訊這三種資訊可能會被打亂順序混合輸入。
為此,我在答題1的基礎上做了一些改動。
題目類:保持原來功能不變;
試卷類:增加了試卷編號、對應的分值,返回試卷總分和題目數量的方法。
答卷類:儲存答卷對應的試卷編號,答案,和判題結果。新增了試卷有效性判斷標誌,並調整了答案評估函式。
主類:增加了試卷集合和答卷集合來確保對多張試卷的處理,儲存並統計試卷及其答案,根據標答判斷答案的正確性,輸出總分警告及每道題的答題結果。
2.1試卷類
number: 記錄試卷中題目的數量。初始化為0,每當新增一道題目時自增1。
matters: 一個 LinkedHashMap 用於儲存題目ID及其對應的分數。使用 LinkedHashMap 是為了維護插入順序,方便後續可能的遍歷操作。
fullpoints: 記錄試卷的總分,初始化為0。每新增一道題目時,該分數累加。
2.2答卷類
id (int): 表示此答卷的唯一識別符號。每個答卷都會有一個 ID,用以唯一識別這份答卷。
counts (int): 表示答卷中題目的數量。這個屬性用於追蹤該份答卷中包含了多少個問題。
answers (List
results (List
方法:返回答卷號 答卷的題目數量 答案列表 記錄每個答案的判題結果並返回
2.3主類
題目、試卷、答案的輸入解析:
透過不同的標誌符(#N:、#T:、#S:)來區分輸入的型別。
對每種輸入型別使用正規表示式來提取相應的資料
檢測到 #N: 開頭的輸入,提取題號、內容和標準答案,建立 Matter 例項並儲存在 matter 中。
檢測到 #T: 開頭的輸入,提取試卷 ID 和題目分數,建立 TestPaper 例項並儲存。
檢測到 #S: 開頭的輸入,提取答卷 ID 和使用者的答案,建立 Responsepaper 例項並儲存在 ans 列表中。
檢查所有試卷的總分:
在評分過程中,檢查每份試卷的總分是否為 100,若不等於 100,輸出警告資訊。
輸出使用者的答案和評分結果:
遍歷每個使用者的答案,獲取對應試卷的資訊,比較使用者的答案與標準答案。
輸出每道題的表現(是否正確)、使用者的答案和題目內容。
計算正確的題目得分並輸出總分
類圖
時序圖
3.答題判題程式3
答題判題程式3在答題判題程式2的基礎上增加了 學生類和刪除題目資訊,在我看來,難度大大增加,讓我望而卻步。
為了實現上述功能,我在原有程式碼基礎上做了一些改動。
3.1InputProcessor 類
增加了一個新的類 InputProcessor,用於處理輸入,減少主類的負擔,增加程式碼後續的移植性。
正規表示式匹配: 使用正規表示式 #N:(\s\d+\s)#Q:(.)#A:(.) 來匹配輸入格式。
字串處理: 透過 indexOf 方法找到特定標記的位置,然後使用 substring 方法提取相關資訊。
資料儲存: 將提取的資訊儲存到 matter 對映中,建立一個新的 Matter 物件並新增到對映中。
功能: 處理試卷輸入。
正規表示式匹配: 使用正規表示式 #T:\s(\d+)\s(\s\d+-\d+\s)* 來匹配輸入格式。
字串處理: 透過 Matcher 物件提取試卷ID和題目ID及對應分數。
資料儲存: 建立一個新的 ExamPaper 物件,並將題目ID和分數新增到 ExamPaper 物件中,最後將 ExamPaper 物件儲存到 exampaper 對映中。
處理學生答案輸入。
正規表示式匹配: 使用正規表示式 #S:\s(\d+)\s+(\w)\s(#A:\s(\d+-?[^#])) 來匹配輸入格式。
字串處理: 透過 Matcher 物件提取試卷ID、學生ID和答案內容。
資料儲存: 將提取的答案內容儲存到 an 對映中,建立一個新的 Answer 物件並新增到 ans 連結串列中。
處理學生資訊輸入。
正規表示式匹配: 使用正規表示式 #X:\s(\d+)\s(.)(-(\d+)\s(.)) 來匹配輸入格式。
字串處理: 透過 Matcher 物件提取學生ID和姓名。
資料儲存: 建立一個新的 Student 物件並新增到 studentlist 連結串列中。
處理無效題目輸入。
正規表示式匹配: 使用正規表示式 #D:N-\s(\d+)\s 來匹配輸入格式。
字串處理: 透過 Matcher 物件提取題目ID。
資料更新: 將對應題目的 judgeanswer 屬性設定為 false,標記該題目為無效。
3.2學生類
定義了學生的屬性和基本操作
3.3答卷類
增加了封裝學生答題資訊功能
3.4主類
- 檢查試卷總分是否為100
for (int indea : exampaper.keySet()) {
ExamPaper paper = exampaper.get(indea);
int totalPoint = paper.getTotalpoint();
if (totalPoint != 100) {
System.out.println("alert: full score of test paper" + indea + " is not 100 points");
}
}
2.處理學生答案
獲取試卷ID: 透過 a.getid() 獲取當前答案對應的試卷ID。
檢查試卷是否存在: 如果試卷不存在,輸出提示資訊並跳過當前答案的處理。
查詢學生: 遍歷 studentlist,查詢與當前答案對應的學生。如果找到學生,設定 symbol 為1,並記錄學生資訊。
遍歷試卷題目: 遍歷當前試卷的所有題目,檢查學生答案是否正確,並將判斷結果儲存到 consequns 列表中。
處理答案輸出:
答案數量為0: 如果答案數量為0,輸出 "answer is null",並輸出學生的總分為0。
答案數量不為0: 遍歷試卷的所有題目,輸出每個題目的答案和判斷結果。如果學生答案存在且題目有效且答案正確,輸出題目的分數;否則輸出0。最後輸出學生的總分。
類圖
時序圖
踩坑心得
1.拖延症,一定要早點開始寫pta大作業,隨著難度的增加,完成一次大作業所需的時間也隨之增加,如果不盡早開始的後果就是完成不了或者質量很差。
2.類的設計簡單,各個類的關聯性不強,導致第三次大作業的難度增加 需要在主類里加很多功能,導致程式碼的簡潔性不強,對於下一次的大作業不能很好遷移。
3.懶惰心理,一開始不願意吸收新知識,正規表示式,導致浪費了很多時間,正規表示式看似複雜實際上實用性很強,能減少本次大作業的不少壓力
4.方法的職責劃分不清晰,導致程式碼難以理解和維護,遵循單一職責原則,每個方法只負責一個特定的任務。
5.程式碼的可讀性很差,應當多加註釋。
改進建議
(1)在程式碼中合理性地增加類的設計,不要把功能堆砌在一個類或者主類中,這樣會使得程式碼贅餘,更難理解,應該逐步將複雜的程式碼拆分成多個小方法,每個方法只做一件事。
(2)核心程式碼部分增加詳盡的註釋
總結
經過三次大作業的洗禮,或許是程式碼寫的少緣故,面對壓軸題的時候,我感覺腦力和精力被壓榨,加上畏難心理,我總是把大題拖到最後來寫,因此又導致了一系列糟糕的連鎖反應,陷入了死迴圈。
所以,紮實的程式碼功力和知識儲備是基石,克服自身的畏難心理也格外重要。其實我們上課認真聽講,總結和內化學堂上和課後學到的知識,並在面對程式碼量大無從下手的程式碼時,畫好類圖和思維導圖,把大難題細化成小難題,逐一攻破,沒有什麼事情是不能迎刃而解的。
這樣便可以,梳理出答題判題程式的總體思路
比如第三次大作業的主要功能是處理學生答題和判題的過程。程式透過讀取使用者輸入的不同型別的資料(如題目、試卷、學生答案和學生資訊),進行相應的處理和儲存,最後輸出判題結果。程式的整體思路可以分為以下幾個步驟:
輸入處理:讀取使用者輸入,根據輸入的不同型別(如題目、試卷、學生答案、學生資訊等)進行相應的處理和儲存。
資料儲存:將處理後的資料儲存到相應的資料結構中(如 LinkedHashMap、LinkedList 等)。
輸出處理:根據儲存的資料進行判題,並輸出判題結果。最終我們需要設計合理的類,透過詳細的註釋和合理的程式碼結構,去提高程式碼的可讀性和可維護
三次大作業不是結束,而是開始,老師說,未來大作業的難度還會提高,所以,道阻且長,行則將至。