题目集OOP1~3心得
1.前言
-
很开心我在三次题目集的攻击下幸存了下来(doge)。
-
三次题目集感受
- 对于第一次题目集,印象不是很深,花了精力但是没有挣扎的感觉,因此印象不深。这次题目集有一个地方值得肯定,就是在题目区域放上了一些建议(虽然建议放的位置偏后在测试用例之后,导致本次写题时并没有注意,但是在第二次题目集采用建议之后,确实有不错的反响)。
- 第二次题目集写的异常顺利,采取了上述建议是一方面,另外一方面也是自己开始的比较早,压力较小。花上三四个小时根据题目编写代码之后,样例和题目测试用例很顺利的都通过了,给了我自信,但同时也因为这样,第三次题目集开始的比较晚,写的不顺利。
- 第三次题目集开始的比较晚,按理说,早一些晚一些对自己来说,都是那些个小时就能完成的事情,不好的地方就在于,你对于这次题目集的想法会被其他人先入为主,其他人有许多点没调出来,那么自己也会处于比较大的压力,害怕同样面对这样棘手的情况(也许只是因为题目集本身比较难)。
-
知识点
- 题目集前面的几道题都是比较基础吧(千万不要用一个println去直接输出答案),很多关于类的内容和题目,目的当然是将同学们的面向过程程序设计转向面向对象程序设计。
- 到了重点的最后一道题答题判断程序,很综合。输入多种多行,需要运用正则表达式来判断输入格式的正误,需要用字符串的工具来对输入进行分割并运用合适的数据类型,尤其是引用数据类型。各类的输入内容先运用一个合适的类封装再进行存储更加推荐。接着,是谁的动作,就将这个行为写在那个类当中,判断和存储。然后进行比对,很多情况,很多不合适的输入,各种互相影响的输入,需要利用好逻辑关系来得出正确的输出。其中,逻辑关系的判断稍复杂,圈复杂度过高是需要好好考虑的。
-
题量
题目量不大,前面的几道题稍微花一些时间就能做出来,测试点也比较容易找。对于最后的大题,要是方法不对,不通用,那么对于后续程序的调试和修改就是比较大大考验了,所以说,程序是很追求通用性的,在改进的时候体现的尤为突出。 -
难度
- 本次题目难度设计还是较为合理的,前面几道题难度不高,但是有考察类与对象的知识,最后一题的难度较大,但是预留的时间足够,是同学们可以接受的程度。
- 其中,对于题目集三的最后一道题的初始版本,需要学生对题目潜在的错误进行评估,对于题目的各种疑难杂症要有一套统一标准的答案,分毫不差,会使人抓狂,在调试过程中找不到突破点是难点!
2.三次源码分析
- 第一次源码分析
![]()
第一次的题目比较简单,并且没有试卷和答卷的要求,因此我们只创建了两个类,一个JAVABean类和一个工具类,Question类用来封装题目信息,而Tool作为工具类,将输入的答案与输入的题目对象进行对比再输出结果。 - 第二次源码分析
![]()
第二次则出现了试卷类和答卷类,因为答者的水平有限,暂时没有运用到继承的思想。将题目的内容封装到创建到题目对象中,我们建议用试卷类和答卷类继承题目的属性这样的话,就可以让这两个类变得更加简洁,同时也让相关的类产生关系。 - 第三次源码分析
![image]()
第三次的题目中继续添加内容,加入学生内容和删除题目的功能,我们也加入对应的类,同时也应该运用继承的思想,让答卷继承学生的属性,以更好地再输出判题结果时,带上学生的信息
3.设计与心得
首先是创建各种类与对象
问题类来封装问题
`
private int num;
private String question;
private String answer;
private int deleteQuestionNum;
`
同时提供判断问题格式是否正确和将内容拆分存储的方法
`
public static boolean IsQuestion(String temp){
String test = "#N:[\\d]+ #Q:[^ ]* #A:[^ ]*";
if(temp.matches(test))
return true;
return false;
}
public static boolean IsDeleteQuestion(String temp){
String test = "#D:N-\\d+";
if(temp.matches(test))
return true;
return false;
}
public Question spiltDeleteQuestion(String s){
this.deleteQuestionNum = Integer.parseInt(s.substring(5));
//System.out.println(this.toString());
return this;
}
public Question spiltQuestion(String s) {
String[] temp = s.split(" ");
this.num = Integer.parseInt(temp[0].substring(3));
this.question = temp[1].substring(3);
this.answer = temp[2].substring(3);
//System.out.println(this.toString());
return this;
}
`
剩下的答案类,答卷类,试卷类同样是这样的思想
答卷
点击查看代码
private int testNum;
private String id;
ArrayList<String> answer = new ArrayList<>();
ArrayList<Integer> num = new ArrayList<>();
ArrayList<Integer> grade = new ArrayList<>();
public static boolean IsAnswer(String temp){
String test = "#S:\\d+ \\d+(\\s)*( #A:\\d+-([\\d]*||\\s))*";
if(temp.matches(test)){
return true;
}
return false;
}
public Answer SpiltAnswer(String s){
String[] str1 = s.split(" ");
this.testNum = Integer.parseInt(str1[0].substring(str1[0].indexOf(':')+1));
this.id = str1[1];
for (int i = 2; i < str1.length; i++) {
String[] temp = str1[i].split("-");
num.add(Integer.parseInt(temp[0].substring(temp[0].indexOf(':') + 1)));
if(temp.length > 1)answer.add(temp[1].trim());
else answer.add("");
}
//System.out.println(this.toString());
return this;
}
试卷
点击查看代码
private int testNum ;
private int sumGrade = 0;
ArrayList<Integer> questionNum = new ArrayList<>();
ArrayList<Integer> questionGrade = new ArrayList<>();
public static boolean IsTestPaper(String temp){
String test = "#T:\\d+( \\d+-\\d+)*";
if(temp.matches(test)) {
return true;
}
return false;
}
public TestPaper spiltTestPaper(String s) {
String []temp = s.split(" ");
for (int i = 0; i < temp.length; i++) {
if(i == 0){
testNum = (Integer.parseInt(temp[i].substring(temp[i].indexOf(":")+1)));
}else{
String []str = temp[i].split("-");
questionNum.add(Integer.parseInt(str[0]));
questionGrade.add(Integer.parseInt(str[1]));
this.sumGrade += Integer.parseInt(str[1]);
}
}
if(this.sumGrade != 100){
System.out.println("alert: full score of test paper" +testNum +" is not 100 points");
}
//System.out.println(this.toString());
return this;
}
输出
点击查看代码
public class Tools {
public static void CheckQuestion(TestPaper testPaper, Answer answer, ArrayList<Question> questions, ArrayList<Question> deletes, Student students) {
String id = answer.getId();
String name = "";
boolean findName = false;
ArrayList<Integer> ActualGrade = new ArrayList<>();
for (int i = 0; i < students.getIdArr().size(); i++) {
if (students.getIdArr().get(i).equals(id)) {
findName = true;
name = students.getNameArr().get(i);
}
}
for (int i = 0; i < testPaper.getQuestionNum().size(); i++) {
int questionNum = testPaper.getQuestionNum().get(i);
boolean findQuestion = true;
for (int j = 0; j < deletes.size(); j++) {
if (deletes.get(j).getDeleteQuestionNum() == questionNum) {
findQuestion = false;
}
}
if (findQuestion) {
boolean existQuestion = false;
for (int k = 0; k < questions.size(); k++) {
if (questions.get(k).getNum() == questionNum) {
existQuestion = true;
questionNum = k;
break;
}
}
if (existQuestion) {
Question question = questions.get(questionNum);
boolean findAnswer = false;
for (int i1 = 0; i1 < answer.getNum().size(); i1++) {
if (answer.getNum().get(i1).equals(i + 1)) {
findAnswer = true;
System.out.printf("%s~%s~", question.getQuestion(), answer.getAnswer().get(i1));
if (answer.getAnswer().get(i1).equals(question.getAnswer())) {
System.out.println("true");
ActualGrade.add(testPaper.getQuestionGrade().get(i));
} else {
System.out.println("false");
ActualGrade.add(0);
}
}
}
if (!findAnswer) {
System.out.println("answer is null");
ActualGrade.add(0);
}
} else {
boolean findAnswer = false;
for (int i1 = 0; i1 < answer.getNum().size(); i1++) {
if (answer.getNum().get(i1).equals(i + 1)) {
findAnswer = true;
}
}
if (findAnswer) {
System.out.println("non-existent question~0");
ActualGrade.add(0);
} else {
System.out.println("answer is null");
ActualGrade.add(0);
}
}
} else {
boolean findAnswer = false;
for (int i1 = 0; i1 < answer.getNum().size(); i1++) {
if (answer.getNum().get(i1).equals(i + 1)) {
findAnswer = true;
}
}
if (findAnswer) {
System.out.println("the question " + questionNum + " invalid~0");
ActualGrade.add(0);
} else {
System.out.println("answer is null");
ActualGrade.add(0);
}
}
}
if(findName) {
System.out.printf("%s %s:", id, name);
int all = 0;
for (int i = 0; i < ActualGrade.size(); i++) {
if (i == 0) {
all = ActualGrade.get(i);
System.out.printf(" %d", ActualGrade.get(i));
} else {
all += ActualGrade.get(i);
System.out.printf(" %d", ActualGrade.get(i));
}
}
System.out.println("~" + all);
}else {
System.out.println(id + " not found");
}
}
}
4.踩坑心得
- 对第三次题目集一直耿耿于怀,不只是第三道题
- 第二道题中,关于两个日期之间的计算,有一个测试调试了比较久,一个原因是被类中的本地变量牵绊住了,没有区分出本地变量和局部变量。
另外一个就是,有很多特殊例子需要考虑,跨年或者不跨年,闰年或者平年,在进行调试的时候建议自己创建边缘测试数据并给出参考答案。
同时,要是已经学习过Date类和Calendar类的话,运用java中自带的类会更容易实现这些问题并且会更加的安全。
- 第二道题中,关于两个日期之间的计算,有一个测试调试了比较久,一个原因是被类中的本地变量牵绊住了,没有区分出本地变量和局部变量。
- 第三题尤其可怕,包括我在内的许多同学都经历过数小时调试而对程序运行毫无作用的感受,如此这样艰难的过程确实会让人丧失信心与耐性。
私以为题目具有一些不完整性,理由如下:在题目中,作者给出了输入的文字格式,并要求学生对错误形式进行判断,可是错误的输入格式同题目给出的文字格式在仅仅依靠为数不多的几个样例是无法建立完整且清晰的关系的。所以,为了避免格式不通用,学生应该提升自身代码的通用性,可是这是一个很难评判的标准,因为你也不知道是否会因为题目限制太严而被卡测试点。
5.改进建议和总结
- 在运用正则表达式方面,还可以更加精简,比如运用贪婪匹配和非贪婪匹配,同时,运用正则表达式能够分组的思想,更好的处理重复出现的代码
点击查看代码
```plaintext
//?=表示在前面的文字基础上,必须匹配11,17,才可以成功
//String regex = "JAVA(?=11|17)";
//?:表示在前面的文字包括后面的条件
//String regex = "JAVA(?:11|17)";
//?!表示在前面的文字基础上,不匹配11,17,才可以成功
//String regex = "JAVA(?!11|17)";
//用(?i)表示忽略大小写
```plaintext
/以左括号为排序基准,组别依次为1,2,3,4……
//用\\(num)来饮用组别
//首尾的第一个相同
String s = "(.).+\\1";
// System.out.println("test".matches(s));//true
// System.out.println("tess".matches(s));//false
//首尾连续的个数相同(最后的元素和开通相同个数的元素相同多)
String s1 = "((.)\\2+).+\\1";
// System.out.println("ttesstt".matches(s1));
// System.out.println("tttest".matches(s1));
//
// String test = "小舞舞saaahgjan小雾雾sagnja小灯灯";
// String s2 = "[\\w&&[^_]]+";
// System.out.println(test.replaceAll(s2,"VS"));
// (\\)用于在组别之内应用($用于在组别之外应用)
//简略文字
String test = "我我我爱编编编编编编程";
String s2 = "(?:(.))\\1*";
//System.out.println(test.replaceAll(s2, "$1"));
//运用 ?! ?: ?= 创建非捕获分组,以免占用空格
//就是在左括号旁边马上用?
String test3 = "JAVA17JDE";
String s3 = "(?:JAVA(17|11)JDE)";
System.out.println(test3.matches(s3));
// System.out.println(test3.replaceAll(s3, "$2"));



浙公网安备 33010602011771号