有关java的博客-3
一、前言
本次博客主是针对java学习第三阶段中的第6-8次PTA题目(成绩计算系列)的总结性博客,第三阶段的作业难度与第一阶段和第二阶段想必有所提高,对java的知识点考察主要集中在类的设计,正则表达式的运用,类的继承,多态,抽象类与接口。
二、设计与分析
1.课程成绩统计程序-1
1)类图

2)生成报表

(绿色环形区域即被测量维度的期望值,维度上的点则是测量得到的实际值)
据报表分析:
①平均圈复杂度和函数深度超标,圈复杂度大,说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。
②耦合度过高:类与类间分支嵌套过多
3)代码解释:
本题我利用到了继承,与Comparable接口。我创建了课程类,学生类,选课类(将学生和课程联系在一起),成绩类,班级类,输出类。其中因为题干所述选修课和必修课的成绩计算方式不同,所以又设计了考试成绩类和考察成绩类分别继承成绩类。
课程类,学生类都继承了Comparable接口,可以按题干要求实现首字母排序。
我在main里面进行了输入的判断,定义了选课信息,班级信息,学生信息的动态数组,进行完输入后,我再将构造好了的选课信息,班级信息,学生信息数组传到输出类里,进行输出。
4)部分代码如下:
class 课程 implements Comparable<课程>{
	String 课程名称;
	String 课程性质;
	String 考核方式;
	public 课程(String 课程名称, String 课程性质, String 考核方式) {
		super();
		this.课程名称 = 课程名称;
		this.课程性质 = 课程性质;
		this.考核方式 = 考核方式;
	}
	@Override
	public int compareTo(课程 o) {//按照课程名字排序
		// TODO Auto-generated method stub
		//return 0;
		String[] arrays=new String[2];
		arrays[0]=this.课程名称;
		arrays[1]=o.课程名称;
		Comparator com = Collator.getInstance(java.util.Locale.CHINA);
		Arrays.sort(arrays, com);
		if(arrays[0].equals(o.课程名称)) {
			return 1;
		}
		if(arrays[0].equals(this.课程名称)) {
			return -1;
		}
		else
			return 0;
			
			          /*char[] c_pre = this.课程名称.toCharArray();
			          char[] c_next = o.课程名称.toCharArray();
			          
			          int minSize = Math.min(c_pre.length, c_next.length);
			          
			          for (int i = 0; i < minSize; i++) {
			              if((int)c_pre[i] > (int)c_next[i]){
			                  return 1;
			              }else if((int)c_pre[i] < (int)c_next[i]){
			                  return -1;
			              }
			          }
			          if(c_pre.length > c_next.length){
			              return 1;
			          }
			          
			    return -1;*/
	}
	
}
class 学生 implements Comparable<学生>{//组合
	String 姓名;
	String 学号;
	public 学生(String 姓名, String 学号) {
		super();
		this.姓名 = 姓名;
		this.学号 = 学号;
	}
	@Override
	public int compareTo(学生 o) {
		// TODO Auto-generated method stub
		String thisx=this.学号.substring(this.学号.length()-2);
		String ox=o.学号.substring(o.学号.length()-2);
		int thisxh=Integer.parseInt(thisx);//this学号
		int oxh=Integer.parseInt(ox);//o学号
		if(thisxh>oxh) {
			return 1;
		}
		if(thisxh<oxh) {
			return -1;
		}
		return 0;
	}
	
}
class 班级 implements Comparable<班级>{
	String 班号;
	ArrayList<学生> students;
	int 参与考试的人数=0;
	double sum=0;
	 public ArrayList<选课> xuanke;
	 
	public 班级(String 班号) {
		students=new ArrayList();
		xuanke=new ArrayList();
		this.班号 = 班号;
	}
	public void 添加学生(学生 stu) {
			 students.add(stu);
		 
	 }
	public void 选课信息添加(选课 choice) {
		xuanke.add(choice);
	}
	public void 计算总成绩平均分(double 成绩) {
		sum=sum+成绩;
		参与考试的人数=参与考试的人数+1;
	}
	@Override
	public int compareTo(班级 o) {
		// TODO Auto-generated method stub
		//String thisx=this.班号.substring(this.班号.length()-2);
		//String ox=o.班号.substring(o.班号.length()-2);
		int thisxh=Integer.parseInt(this.班号);//this学号
		int oxh=Integer.parseInt(o.班号);//o学号
		if(thisxh>oxh) {
			return 1;
		}
		if(thisxh<oxh) {
			return -1;
		}
		return 0;
	}
	
}
class 成绩{
	public double 总成绩;
	public double 平时成绩=0;
	public double 期末成绩;
	public 成绩() {
		super();
	}
	
	
	/*double 平时成绩;
	double 期末成绩;
	double 总成绩;*/
}
class 考试成绩 extends 成绩{
	int 平时成绩;
	int 期末成绩;
	public 考试成绩(int 平时成绩, int 期末成绩) {
		super();
		this.平时成绩 = 平时成绩;
		this.期末成绩 = 期末成绩;
		super.平时成绩=平时成绩;
		super.期末成绩=期末成绩;
		总成绩=(平时成绩*0.3+期末成绩*0.7);
	}
}
class 考察成绩 extends 成绩{
	int 期末成绩;
	public 考察成绩(int 期末成绩) {
		super();
		this.期末成绩 = 期末成绩;
		
		总成绩=(期末成绩);
	}
	
}
class 选课{
	学生 学生a;
	String  课程a;
	public 成绩 成绩a;
	public 选课(学生 学生a, String 课程a, 成绩 成绩a) {
		super();
		this.学生a = 学生a;
		this.课程a = 课程a;
		this.成绩a = 成绩a;
	}
}
class 输出{
	ArrayList<课程>lesson;//课程信息
	ArrayList <班级>classes;//班级信息
	ArrayList <选课>choice;//课程学生成绩信息;
	public 输出(ArrayList<课程> lesson, ArrayList<班级> classes, ArrayList<选课> choice) {
		super();
		this.lesson = lesson;
		this.classes = classes;
		this.choice = choice;
	}
	public void systemoutStudent() {//1)学生课程总成绩平均分按学号由低到高排序输出,格式:学号+英文空格+姓名+英文空格+总成绩平均分
		
		
		for(int i=0;i<classes.size();i++) {
			
			if(classes.get(i)!=null) {
				Collections.sort(classes.get(i).students);
				for(int k=0;k<classes.get(i).students.size();k++) {//一个班级里所有学生k的循环
					int flag=1;//判断该学生是否有成绩
					double sum=0;//每个学生的总成绩
					double count=0;
				for(int j=0;j<classes.get(i).xuanke.size();j++) {//一个班里期中一个学生k的所有选课成绩
				
					if(classes.get(i).xuanke.get(j).学生a.学号.equals(classes.get(i).students.get(k).学号)) {
						flag=0;
					sum=sum+classes.get(i).xuanke.get(j).成绩a.总成绩;
					count=count+1;
					
				}
					
					
				}
				
				if(flag==1) {//如果某个学生没有任何成绩信息,输出:学号+英文空格+姓名+英文空格+"did not take any exams"
					System.out.println(classes.get(i).students.get(k).学号+" "+classes.get(i).students.get(k).姓名+" "+"did not take any exams");
				}
				if(flag==0) {
					System.out.println(classes.get(i).students.get(k).学号+" "+classes.get(i).students.get(k).姓名+" "+(int)Math.floor(sum/count));
					classes.get(i).计算总成绩平均分(Math.floor(sum/count));
				}
			}
		}
		}
	}
	public void systemoutClasses() {//班级所有课程总成绩平均分按班级由低到高排序输出
		for(int i=0;i<classes.size();i++) {
			double sum=0;
			int flagg=0;
			for(int j=0;j<classes.get(i).xuanke.size();j++) {
				flagg=1;
				
			}
			if(flagg==1) {//有sum班级名称+英文空格+ "has no grades yet"//班级号+英文空格+总成绩平均分
				
				System.out.println(classes.get(i).班号+" "+(int)Math.floor(classes.get(i).sum/(double)classes.get(i).参与考试的人数));
			}
			if(flagg==0) {//该班级没有分数
				System.out.println(classes.get(i).班号+" has no grades yet");
			}
		}
	}
	public void systemoutLesson() {//单门课程成绩平均分分为三个分值:平时成绩平均分(可选)、期末考试平均分、总成绩平均分,按课程名称的字符顺序输出
		//格式:课程名称+英文空格+平时成绩平均分+英文空格+期末考试平均分+英文空格+总成绩平均分
		//如果某门课程没有任何成绩信息,输出:课程名称+英文空格+"has no grades yet"
		
		for(int i=0;i<lesson.size();i++) {//遍历课程表
			double 平时成绩=0;
			double 期末成绩=0;
			double 总成绩=0;
			int flag=2;//判断该课程是否有成绩,2是没有,1是考试,0是考察
			double count=0;//考试人数
			课程 kc=lesson.get(i);//kc是某节课
			for(int j=0;j<choice.size();j++) {//遍历选课信息,找到kc这堂课对应的成绩
				if(choice.get(j).课程a.equals(kc.课程名称)) {
					if(kc.考核方式.equals("考试")) {//找到之后,看对应的考核方式,考试的话就要累加平时成绩与期末成绩和总成绩
						flag=1;
						平时成绩=平时成绩+choice.get(j).成绩a.平时成绩;
						期末成绩=期末成绩+choice.get(j).成绩a.期末成绩;
						总成绩=总成绩+choice.get(j).成绩a.总成绩;
						count++;
					}
					if(kc.考核方式.equals("考察")) {//考察,choice.get(j)是找到的对应kc的选课信息
						flag=0;
						总成绩=总成绩+choice.get(j).成绩a.总成绩;
						count=count+1.0;
					}
					
				}
			}
			//格式:课程名称+英文空格+平时成绩平均分+英文空格+期末考试平均分+英文空格+总成绩平均分
			if(flag==0) {//考察
				System.out.println(kc.课程名称+" "+(int)Math.floor(总成绩/count)+" "+(int)Math.floor(总成绩/count));
			}
			if(flag==1) {//考试
				System.out.println(kc.课程名称+" "+(int)Math.floor(平时成绩/count)+" "+(int)Math.floor(期末成绩/count)+" "+(int)Math.floor(总成绩/count));
			}
			if(flag==2) {//没分!输出:课程名称+英文空格+"has no grades yet"
				
				System.out.println(kc.课程名称+" "+"has no grades yet");
			}
		}
	}
}
2.课程成绩统计程序-2
1)类图

2)生成报表

(绿色环形区域即被测量维度的期望值,维度上的点则是测量得到的实际值)
据报表分析:
①平均圈复杂度和函数深度超标,圈复杂度大说明程序代码的判断逻辑复杂,代码质量较低(其实是因为我把判断输入是否正确的代码大部分都放在了主函数,所以主函数写的过于冗长)
②耦合度过高:类与类间分支嵌套过多。
3)代码解释:
课程成绩统计程序-2在第一次的基础上增加了实验课,如果上一次作业的类设计比较清晰的话,其实这次作业比较容易完成。
这次我在上次代码的基础上,新增了一个实验成绩类,同样是继承成绩类,可以看到代码如下:
class 实验成绩 extends 成绩{ ArrayList<Integer> 实验分数=new ArrayList<Integer>(); public 实验成绩(ArrayList<Integer> 实验分数) { super(); this.实验分数 = 实验分数; int sum=0; for(int i=0;i<实验分数.size();i++) { sum=实验分数.get(i)+sum; } 总成绩=sum/实验分数.size(); } }
这个实验类里面有一个ArrayList数组用来存放实验分数,这是因为实验成绩的分数的数量是不固定的,所以用ArrayList数组刚刚好。
除此之外,改动还有在main方法中新增了判断实验成绩,实验课的部分,输出类也增添了输出实验成绩的部分。
4)部分相比之前修改过的代码如下:
(main方法里新增的判断实验成绩的一栏)
else if(brr.length>5&&brr[0].matches("^[0-9]{8}$")&&brr[1].length()<=10&&brr[2].length()<=10&&isNum(brr[3])) { if(!(Integer.parseInt(brr[3])>=4&&Integer.parseInt(brr[3])<=9)) { System.out.println("wrong format"); continue; } int x=0; int yc=0; int flagg=0; String arr[]=l.split(" "); for(int i=0;i<arr.length;i++) { if(i>=4) { if(Integer.parseInt(arr[i])>100||Integer.parseInt(arr[i])<0) { System.out.println("wrong format"); flagg=1; break; } } } if(flagg==1) { continue; } String 班号=arr[0].substring(0,6); for(String s:成绩记录) {//添加过该条成绩 if(s.equals(arr[0]+arr[1]+arr[2])) { x=1; } } if(x==1) { continue; } 成绩记录.add(arr[0]+arr[1]+arr[2]); 学生 stu=new 学生(arr[1], arr[0]); int flag=0;//如果班号存过 for(int i=0;i<classes.size();i++) { if(班号.equals(classes.get(i).班号)) { flag=1;//班号存过 int temp=1;//1是没存过,0是存过 for(学生 b:classes.get(i).students) { if(b.学号.equals(stu.学号)) { temp=0; break; } } if(temp==1) { classes.get(i).添加学生(stu); } break; } }//flag=1; if(flag==0) {//班号没存过 班级 bj=new 班级(班号); bj.添加学生(stu); classes.add(bj); }//把学生添加到班级里 String typle=Typleoflesson(lesson, arr[2]);/// if(typle==null) {//学号+英文空格+姓名+英文空格+":"+课程名称+英文空格+"does not exist" //System.out.println(arr[0]+" "+arr[1]+" "+arr[2]+" "+"dose not exist"); System.out.println(arr[2]+" does not exist"); yc=1; } else if(typle.equals("实验")) { int num=Integer.parseInt(brr[3]); if((arr.length-4)!=num) { System.out.println(arr[0]+" "+arr[1]+" "+": access mode mismatch");// } else { ArrayList<Integer>xy=new ArrayList<Integer>(); for(int i=0;i<arr.length;i++) { if(i>=4) { xy.add(Integer.parseInt(arr[i])); } } 实验成绩 k=new 实验成绩(xy); 选课 choose=new 选课(stu, arr[2], k); for(int i=0;i<classes.size();i++) { if(班号.equals(classes.get(i).班号)) { classes.get(i).选课信息添加(choose); } } choice.add(choose); } } }
3.课程成绩统计程序-3
1)类图

2)生成报表

3)代码解释:
课程成绩统计程序-3在第二次的基础上修改了计算总成绩的方式。
考试课程成绩和实验课程成绩增加了一个“权重”部分,这个部分的修改我是通过修改实验成绩类,考试成绩类来实现:在实验成绩类中增加一个ArrayList数组,用来存放各个成绩的权重,考试成绩类的修改同上。
与此同时,我还在main方法中修改了相应输入格式的判断。
4)部分修改的代码如下:
class 实验课程 extends 课程{ ArrayList<Double>权重=new ArrayList(); public 实验课程(String 课程名称, String 课程性质, String 考核方式, ArrayList<Double> 权重) { super(课程名称, 课程性质, 考核方式); this.权重 = 权重; } } class 考试成绩 extends 成绩{ int 平时成绩=0; int 期末成绩=0; ArrayList<Double>权重=new ArrayList<Double>(); public 考试成绩(int 平时成绩, int 期末成绩, ArrayList<Double> 权重) { super(); this.平时成绩 = 平时成绩; this.期末成绩 = 期末成绩; this.权重 = 权重; 总成绩=(平时成绩*权重.get(0)+期末成绩*权重.get(1)); } }
三、踩坑心得
- 写正则表达式
 
由于正则表达式过于不熟练,导致最后一次大作业好多测试点都没有过,之后我上网看了有关正则表达式的文章,学习了一下后运用到代码里,发现真的很方便。
这里给出我当时学习正则表达式用的文章:
[]:http://t.csdn.cn/ZmH67
- Comparable接口
 
,Comparable的comepareTo方法搭配Collection.sort()方法可以实现对对象数组的排序,十分方便。
- 格式错误的踩坑
 
错误格式是因为漏了空格或多了回车,这需要不断调试代码并且对比题干才可以发现这类错误的原因。
还有就是非零返回,这个错误真的很头疼,因为你不知道什么时候在哪里忘记判断非空,然后你就要从头到尾看代码来找错误。
- 审题与类设计
java是面向对象的语言,在题目给出后,应该先认真审题,将类都设计好,不然到后续发现漏了题目要求的时候,改起来很复杂。
同样,为了方便修改代码内容,应该降低类之间耦合性,熟悉类间关系进行设计。 
四、主要困难与改进建议
①主要困难:
基础知识薄弱,对于很多新的语法不会用不敢用,如最近接触的哈希,Hashmap,Hashset。
②改进建议:
在写代码时候要充分考虑代码的可重用性和可扩展性,设计合适的类和方法。并且在进行问题排查和错误修改时,要使用合适的调试工具和技术,例如断点调试。同时加强对编程语言的训练,以提高开发效率和代码质量。
五、总结
经历了java第三个学习阶段,我深刻认识到在面向对象过程中对类的设计是多么重要,类与类间关系,接口和抽象类的设计等等,都是对我的考验。代码越好,代码的圈复杂度就越低,类与类之间关系明确,代码的可维护性也高。
再回归具体知识点,在本阶段学习中我训练了继承和接口的使用,也自主设计了面向对象的代码,并逐步接触了一些比较好用的类与方法,也对动态数组的使用逐渐熟悉。希望在学好目前的知识的基础上,能学到更深的知识。
与此同时也掌握了java编程工具和框架,如Eclipse。
                    
                
                
            
        
浙公网安备 33010602011771号