第三次blog
PTA电信计费(部分代码):
abstract class CallChargeRule extends ChargeRule{
public abstract double calCost(ArrayList<CallRecord> callRecords);
}
class LandPhoneInLandRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
long interval;
double cost = 0;
for(int i = 0; i < callRecords.size(); i++){
interval = callRecords.get(i).getEndTime().getTime() - callRecords.get(i).getStartTime().getTime();
if(interval % 60000 == 0){
interval = interval / 60000;
} else {
interval = interval / 60000 +1;
}
cost = cost + interval*0.6;
}
return cost;
}
}
class LandPhoneInCityRule extends CallChargeRule{
@Override
public double calCost(ArrayList<CallRecord> callRecords) {
long interval;
double cost = 0;
for(int i = 0; i < callRecords.size(); i++){
interval = callRecords.get(i).getEndTime().getTime() - callRecords.get(i).getStartTime().getTime();
if(interval % 60000 == 0){
interval = interval / 60000;
} else {
interval = interval / 60000 +1;
}
cost = cost + interval*0.1;
}
return cost;
}
}
相应类图:

题目所给类图中,包含了计费功能和通话记录的分离的设计,继承与多态的灵活运用。
手机+座机计费(部分代码):
class User { private UserRecords userRecords = new UserRecords(); private double balance = 100; private ChargeMode chargeMode; private String number; public void calBalance() { balance = balance - calCost() - chargeMode.getMonthlyRent(); } public double calCost() { return chargeMode.calCost(userRecords) ; } public UserRecords getUserRecords() { return userRecords; } public void setUserRecords(UserRecords userRecords) { this.userRecords = userRecords; } public double getBalance() { return balance; } public ChargeMode getChargeMode() { return chargeMode; } public void setChargeMode(ChargeMode chargeMode) { this.chargeMode = chargeMode; } public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } }
相应类图:

短信计费(部分代码):
class LandPhoneInLandRule extends CallChargeRule{ @Override public double calCost(ArrayList<CallRecord> callRecords) { long interval; double cost = 0; for(int i = 0; i < callRecords.size(); i++){ interval = callRecords.get(i).getEndTime().getTime() - callRecords.get(i).getStartTime().getTime(); if(interval % 60000 == 0){ interval = interval / 60000; } else { interval = interval / 60000 +1; } cost = cost + interval*0.6; } return cost; } } class LandPhoneInCityRule extends CallChargeRule{ @Override public double calCost(ArrayList<CallRecord> callRecords) { long interval; double cost = 0; for(int i = 0; i < callRecords.size(); i++){ interval = callRecords.get(i).getEndTime().getTime() - callRecords.get(i).getStartTime().getTime(); if(interval % 60000 == 0){ interval = interval / 60000; } else { interval = interval / 60000 +1; } cost = cost + interval*0.1; } return cost; } }
相应类图:

总结:这三次电信计费练习涉及了许多输入有效性的判断,具体思路:创建一个可储存用户的容器,判断输入的信息,如果判断为开户信息,再判断容器中是否存在相同的账户号码,不存在则在容器中添加该用户,如果判断为通话信息,在判断拨打号码和收听号码是否是容器中的号码,若是则将拨打(收听)信息存入用户中的储存相应信息的容器中,最后的计费则是将用户里的每条拨打信息的时间提取出来进行计算即可;对于这次题目集我最大的收获是认识到了一个合理的设计的重要性,由于代码是基于第一次题目集所给的类图上设计的,对于后面的题目集所做出的功能拓展我不需要改变太多代码就能实现功能,如果让我设计的话,可能每次题目集都要将代码进行大幅度修改才能实现相应功能。
(1)题目集1-3前言:
题目集1~3:Java pta 题目集一的题目比较简单,一共有9个编程题,虽然题目量比较大,但是考察的都是比较基础的知识,主要考察Java的输入输出以及一些语法的使用,比如判断三角形类型、学号的识别、游戏角色选择等等。语法方面和C语言比较相似,只是表达方式不太一样,第一次大作业也是顺利的拿下了满分,完成这一次大作业后,我对Java语言有了最基本的概念,题目集中用到的for循环、if else 嵌套、switch case 都是和C语言相通的,但在完成作业过程中也遇到了一些困难,比如第八题的二进制数值提取中把-1拆为‘-’和‘1’分别判断,还有测试点中要用float强制转换成浮点数我尝试了很多次才通过,总的来说第一次大作业让我熟悉了Java语言的语法,慢慢从C语言转变过来。
题目集二的题目相对题目集一难一些,但是题目量不多,只有三道题,需要用到字符串处理String,用for循环对字符串进行遍历,还有将26个字母转换为序号,考察了我们对二进制的处理怎样应用到字符串上,以及Java中的数学函数,Math.pow的使用,考察了Java数组的知识,第三题String的格式判断与内容提取考察我们从字符串中提取学号,这里比较难过的一个知识点是考虑学号之间是否有空格,对这方面的知识不太了解所以最后导致有两个测试点没有得到分,总结就是老师讲的新内容要及时复习并运用。
题目集三的题目比前两个要难许多,题目量也是三道题,第一题需要将坐标中的数字提取出来进行两点之间的距离计算,但光是这个坐标里面带有逗号就把我难住了,而且两个坐标之间需要用空格分开,需要判断输入的坐标的x、y的正负。然而第一题只是后两题的基础,完不成第一题那后面两题也是做不出来的,后两题需要实现的功能更多,甚至需要一定的数学知识,比如第三题中输入四个点坐标,输出第一个是否在后三个点所构成的三角形的内部,都是很难解决的问题。
(2)设计与分析:
题目集二7-2:串口字符解析
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String A = in.next();
int flag = 0;
if(A.length() <= 10) {
System.out.print("null data");
}
for(int j = 0;j < A.length();j++) {
if(A.charAt(j) == '0') {
flag = 1;
}
}
if(flag == 0) {
System.out.print("null data");
}
else {
int begin = 0,i=0,num = 1,sum = 0;
int a = 0,b = 0;
for(begin = 0;begin < A.length()-10;begin++) {
if(A.charAt(begin) == '0') {
System.out.print(num+":");
num++;
if(A.charAt(begin+10) == '0') {
b = 0;
}
else {
b = 1;
sum = 0;
for(i = begin+1;i < begin+9;i++) {
if(A.charAt(i) == '1') {
sum++;
}
}
if(sum%2 == 0) {
if(A.charAt(begin+9) == '1') {
a = 1;
}
else {
a = 0;
}
}
else {
if(A.charAt(begin+9) == '0') {
a = 1;
}
else {
a = 0;
}
}
}
if(b == 1) {
if(a == 1) {
for(i = begin+1;i < begin+9;i++) {
System.out.print(A.charAt(i));
}
System.out.print("\n");
}
else {
System.out.println("parity check error");
}
}
else {
System.out.println("validate error");
}
begin += 10;
}
}
}
}
}
本题需要从一组字符串数据中过滤掉空闲、起始、结束以及奇偶校验位之后的数据,并对一些非法输入进行相应输出,要用到
charAt(i);
将字符串中的元素进行遍历,然后再看看是1还是0进行数字的运算,然后在进行格式化输出,在这些运算之前,我们首先要判断这串字符是不是合法,运用到
String.length();
函数
题目集三7-1: 点线形系列1-计算两点之间的距离(部分代码)
public boolean test(String a)
{
String judge ="^([-+]?\\d+)(\\.\\d+)?,([-+]?\\d+)(\\.\\d+)?$";
boolean z=a.matches(judge);
if(z==true)
{
for(int j = 0 ; j < a.length() ; j++)
{
if(a.charAt(j) == ',')
{
x=Double.parseDouble(a.substring(0,j));
y=Double.parseDouble(a.substring(j+1,a.length()));
}
}
}
return z;
}
}
用了正则表达式(正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑)
String judge ="^([-+]?\\d+)(\\.\\d+)?,([-+]?\\d+)(\\.\\d+)?$";
可以通过一些特殊符号,实现快速查找、删除、替换某个特定字符串。
题目集7-2:7-2 点线形系列2-线的计算 (部分代码)
public static void fn1(String s) {
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
for(int i = 0; i < s.length()-1; i++)
{
char a = s.charAt(i);
char b = s.charAt(i+1);
if(a==':'){
flag1++;
}
else if(a==',') {
flag2++;
}
else if(a==' ') {
flag3++;
}
if((a=='+'&&b=='+')||(a=='-'&&b=='-'))
{
System.out.print("Wrong Format");
return;
}
}
if(flag1!=1||flag2!=2||flag3!=1)
{
System.out.print("Wrong Format");
}
else {
String s1 = s.replaceAll(":",",");
String s2 = s1.replaceAll(" ",",");
String[] num = s2.split(",");
double a = Double.parseDouble(num[1]);
double b = Double.parseDouble(num[2]);
double c = Double.parseDouble(num[3]);
double d = Double.parseDouble(num[4]);
if(a==c&&b==d)
{
System.out.print("points coincide");
}
else if(a==c&&b!=d)
{
System.out.print("Slope does not exist");
}
else
{
double xl=(b-d)/(a-c);
System.out.print(xl);
}
}
}
这段代码为计算斜率的方法
String[] num = s2.split(",");
通过这个可以将坐标中逗号去掉留下数字。
题目集三7-3:点线形系列3-三角形的计算 (部分代码)
class coordinate
{
double x;
double y;
public boolean test(String a)
{
boolean z=a.matches(judge);
if(z==true)
{
for(int j = 0 ; j < a.length() ; j++)
{
if(a.charAt(j) == ',')
{
x=Double.parseDouble(a.substring(0,j));
y=Double.parseDouble(a.substring(j+1,a.length()));
}
}
}
return z;
}
}
正则表达式
定义:正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,简单来说,是一种匹配字符串的方法,通过一些特殊符号,实现快速查找、删除、替换某个特定字符串
用途:正则表达式会与系统管理员来说非常重要,系统运行过程中会产生大量的信息,这些信息有些是非常重要的,有些则仅是告知的信息。身为系统管理员如果直接看这么多的信息数据,无法快速定位到的重要信息,如“用户账号登陆失败”“服务启动失败”等信息。这时可以通过正则表达式快速提取“有问题”的信息。如此一来,可以将运维工作变得更加简单、方便。
分类正则表达式的字符串表达方式根据不同的严谨程度与功能分为基本正则表达式与扩展正则表达式。基础正则表达式是常用正则表达式最基础的部分。在Linux系统中常见的文件处理工具中grep与sed支持基础正则表达式,二egrep与awk支持扩展正则表达式。
String judge ="^([-+]?\\d+)(\\.\\d+)?,([-+]?\\d+)(\\.\\d+)?$";
- 使用String类的matches方法可以进行整个字符串的匹配,判断某些字符串是否符合相关的规则。只要有一处不符合规则就会返回false,如果都符合返回true。如: 在用matches方法进行判断时,会从字符串开始处依次向下进行匹配,当发现不匹配时,匹配结束,后面的字符不会进行匹配了。
(1)PTA题目集、超星作业以及期中考试的总结性前言
知识点总结:
1.对象的继承关系.
2.对于抽象类的认识与使用.
3.对于四边形的各种形状判断和面积分割的方法求解.
4.正则表达式的使用.
5.ArrayList类中的增、删、减、查的各个作用.
题目量:题目集四共三道,期中考试共三道,农夫过河一道.
题目难度:题目集四中的三、四尤其是三较难,期中考试三道题难度是过渡的,一、二、三三道题难度依次增大,其中第三道是有关容器类保存点 、线、面难度较大,农夫过河给了大部分源代码,只需要加上一些父类添加适合的属性和方。
(2)设计与分析:
题目集四7-1 sdut-String-2 识蛟龙号载人深潜,立科技报国志(II)(正则表达式):
import java.util.Scanner;
import java.util.Arrays;
public class Main{
public static void main(String[] args){
Scanner in=new Scanner(System.in);
while(true){
String s=in.nextLine();
if(s.equals("end")){
break;
}else{
String[] a=s.split("\\D+");
int sum=0;
for(int i=0 ; i<a.length; i++){
if(!a[i].equals("")){
int number = Integer.parseInt(a[i]);
sum+=number;
}
}
System.out.println(sum);
}
}
}
}
本题体现了正则表达式的使用,实现如下功能:读入关于蛟龙号载人潜水器探测数据的多行字符串,从给定的信息找出数字字符,输出每行的数字之和。
题目集四7-2 点线形系列4-凸四边形的计算(部分代码):
题目要求:用户输入一组选项和数据,进行与四边形有关的计算。
以下四边形顶点的坐标要求按顺序依次输入,连续输入的两个顶点是相邻顶点,第一个和最后一个输入的顶点相邻。
public static void fn(String s) {
int flag1 = 0;
int flag2 = 0;
int flag3 = 0;
boolean sibian = true;
boolean pxsibian = false;
for(int i = 0; i < s.length()-1; i++)
{
char a = s.charAt(i);
char b = s.charAt(i+1);
if(a==':'){
flag1++;
}
else if(a==',') {
flag2++;
}
else if(a==' ') {
flag3++;
}
if((a=='+'&&b=='+')||(a=='-'&&b=='-'))
{
System.out.print("Wrong Format");
return;
}
}
if(flag1!=1||flag2!=4||flag3!=3)
{
System.out.print("Wrong Format");
}
else {
String s1 = s.replaceAll(":",",");
String s2 = s1.replaceAll(" ",",");
String[] num = s2.split(",");
double[] a = new double[8];
for(int i=0;i<8;i++) {
a[i] = Double.parseDouble(num[i+1]);
}
double k1 = (a[3]-a[1])/(a[2]-a[0]);
double k2 = (a[5]-a[3])/(a[4]-a[2]);
double k3 = (a[7]-a[5])/(a[6]-a[4]);
double k4 = (a[1]-a[7])/(a[0]-a[6]);
if((Math.abs(a[0]-a[2])<0.1&&Math.abs(a[1]-a[3])<0.1)||(Math.abs(a[2]-a[4])<0.1&&Math.abs(a[3]-a[5])<0.1)||(Math.abs(a[4]-a[6])<0.1&&Math.abs(a[5]-a[7])<0.1)||(Math.abs(a[6]-a[0])<0.1&&Math.abs(a[7]-a[1])<0.1)) {
System.out.println("points coincide");
return;
}
if((Math.abs(k1-k2)<0.1)||(Math.abs(k1-k4)<0.1)||(Math.abs(k2-k3)<0.1)||(Math.abs(k3-k4)<0.1)) {
sibian=false;
}
else if((Math.abs(k1-k3)<0.1&&Math.abs(k2-k4)<0.1)){
pxsibian = true;
}
System.out.println(sibian+" "+pxsibian);
}
}
}
用正则表达式的匹配规则来判断输入的坐标是否正确
代码质量检查:
本题大多涉及数学方面的计算以及判断
矢量叉积
计算矢量叉积是与直线和线段相关算法的核心部分。设矢量P = ( x1, y1 ),Q = ( x2, y2 ),则矢量叉积定义为由(0,0)、p1、p2和p1+p2所组成的平行四边形的带符号的面积,即:P × Q = x1y2 - x2y1,其结果是一个标量。显然有性质 P × Q = - ( Q × P ) 和 P × ( - Q ) = - ( P × Q )。一般在不加说明的情况下,本文下述算法中所有的点都看作矢量,两点的加减法就是矢量相加减,而点的乘法则看作矢量叉积。
期中考试PTA1:7-1 点与线(类设计) :题目要求,
-
设计一个类表示平面直角坐标系上的点Point,私有属性分别为横坐标x与纵坐标y,数据类型均为实型数,除构造方法以及属性的getter与setter方法外,定义一个用于显示信息的方法display(),用来输出该坐标点的坐标信息,格式如下:
(x,y),数值保留两位小数。为简化题目,其中,坐标点的取值范围设定为(0,200]。若输入有误,系统则直接输出Wrong Format - 设计一个类表示平面直角坐标系上的线Line,私有属性除了标识线段两端的点point1、point2外,还有一个字符串类型的color,用于表示该线段的颜色,同样,除构造方法以及属性的getter与setter方法外,定义一个用于计算该线段长度的方法getDistance(),还有一个用于显示信息的方法display(),用来输出线段的相关信息
设计类图如下图所示:

部分代码:
class Point{
private double x;
private double y;
public void Point(double x,double y){
this.x=x;
this.y=y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x=x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y=y;
}
public void display() {
System.out.println("The line's begin point's Coordinate is:()");
System.out.println("The line's begin point's Coordinate is:()");
System.out.println("The line's length is:");
}
}
代码质量检查:

该题目的解决的关键就是认识到类的哪些属性或者方法是私有的还是公有
期中考试7-2 点线面问题重构(继承与多态):题目要求,
- 对题目中的点Point类和线Line类进行进一步抽象,定义一个两个类的共同父类Element(抽象类),将display()方法在该方法中进行声明(抽象方法),将Point类和Line类作为该类的子类。
- 再定义一个Element类的子类面Plane,该类只有一个私有属性颜色color,除了构造方法和属性的getter、setter方法外,display()方法用于输出面的颜色,输出格式如下:
The Plane's color is:颜色
类结构如下图所示:

解决问题的关键在于是否理解抽象方法的定义和是否可以正确的使用。
期中考试7-3 点线面问题再重构(容器类):
类图如下所示

ArrayList类中的增、删、减、查的各个作用.
农夫过河问题(实验):题目要求,
(1)为之前的类添加合适的父类。
(2)为父类添加适合的属性和方法。并以此为基础修改原有的类,使之与添加的类构成继承关系。
(3)使用多态改进整个代码,提高代码的复用性。
(类图)
狼、羊、菜、农夫类:
class Wolf {
boolean crossRiver = true;
boolean hasCross = false;
boolean isAlive = true;
void eatSheep(Sheep sheep,Farmer farmer)
{
if((hasCross&&sheep.hasCross&&!farmer.hasCross)||(crossRiver&&sheep.crossRiver&&!farmer.crossRiver)) {
sheep.isAlive = false;
}
}
void showStatus() {
System.out.println("Wolf is alive:"+isAlive +"\t"+ "Wolf has Cross:"+hasCross);
}
}
class Sheep {
boolean crossRiver = true;
boolean hasCross = false;
boolean isAlive = true;
void eatCabbage(Cabbage cabbage,Farmer farmer)
{
if((hasCross&&cabbage.hasCross&&!farmer.hasCross)||(crossRiver&&cabbage.crossRiver&&!farmer.crossRiver)) {
cabbage.isAlive = false;
}
}
void showStatus() {
System.out.println("Sheep is alive:"+isAlive +"\t"+ "Sheep has Cross:"+hasCross);
}
}
class Cabbage {
boolean crossRiver = true;
boolean hasCross = false;
boolean isAlive = true;
void showStatus() {
System.out.println("Cabbage is alive:"+isAlive +"\t"+ "Cabbage has Cross:"+hasCross);
}
}
class Farmer {
boolean crossRiver = true;
boolean hasCross = false;
void showStatus() {
System.out.println("Farmer has cross:"+hasCross);
}
}
代码质量检测:

农夫、白菜、狼、羊之间的关系的理解
可以将农夫的CrossRiver来作为静态变量,然后将农夫的CrossRiver作为父类的属性来供给子类的引用
这样做:
- 将农夫(Farmer)中的CrossRiver进行标号(public static boolean crossRiver);
- 然后Sheep和cabbage和Wolf用extends Farmer来使用Farmer 的crossRiver;
- 在做农夫过河的问题是农夫过不了河
解决方法
将所有的生物的属性改为静态属性
而且在代码撰写的过程中,我们需要注意的时对象中的属性的可变、不变性,并根据题目来进行对应的处理
在对于题目的理解中,切不可偏僻,要理解全面否则就会出现代码异常的问题;
所以从理论上来说,通过Java的这种继承关系可以规范化编程。
(3)踩坑心得:
1.处理父类和子类关系时,要了解继承的关系和逻辑。
2.在对字符串进行处理时,最好先遍历一遍整个字符串。
3.仔细阅读这些作业中所出现的知识点,将其中所有的约束条件进行代码的单元测试。
(4)改进建议:
1.应当养成良好的编程习惯,使自己的代码看起来容易理解,自己能看懂,加上一些必要的注释使别人也能看懂代码的作用。
2.对于变量的命名做到和变量有关系,让人看见变量名就能知道这个变量是什么。
3.以后的代码编写,应尽量少使用if语句,减少自己的圈复杂度,提高自己代码的效率。
4.知识都是主动摄取的,不是被动灌输的,要提前学习Java,这样才能跟上老师的步伐。
5.加快敲代码的速度,这需要日积月累不断地坚持。
6.对于新知识,如正则表达式应当主动去学习并应用,不要拖到需要用时才开始学。
7.只有边学习边敲代码才能得到进步,光看视频或是听老师讲课是远远不够的。
8.希望发布题目时多一些提示。
对本阶段(10-16周)综合性总结:
1.Java需要循序渐进而且系统的学习方案,不要想着天上掉馅饼的速成方式,给自己制定一个学习计划,制定好每天学习的新知识,然后用什么案例和练习巩固你每天学习的新东西。系统的学习教程,自学Java肯定是主视频,副书籍,因为书大多数人是看不下去的,所以视频要新颖,要系统,不要杂乱不精。
2.学习中需要注意一些问题:开始养成良好代码习惯;先自己多思考,然后再去问老师,培养自己解决问题能力。大量时间用来写代码,而不是看视频。书籍用来回顾知识点,而不要用来一页一页翻书。提高学习效率,一个问题不要在意太久,规划好每天做的事情,完成就行,贪多嚼不烂。
3.好的代码不是一下子写出来的,而是慢慢改出来的,一遍遍的测试一遍遍的修改后得出来的代码才经得住推敲,才经得起使用,一点点的完善,一步步的走向完美。
4.在课程结束之际接触到JavaFX。与C语言课程设计中使用的EGE相比较。Java FX拥有更加美观的样式。同时代码也具有较为固定格式,易于编写。编写内容更加直观。在之前学习中接触到内部类的相关概念与知识。在学习过后对于内部类的实际作用依旧不深刻。在JavaFX事件驱动编程部分。将处理器作为内部类使用的做法使我对于内部类的作用有了新的认识。同时lambda表达式的使用使我感到新奇与特别。相较于以往繁杂的编写,lambda表达式更加简洁明了。
5.最后对于本学期Java课程,希望在之后的课程中可以适当增加课时数,使得能够对于Java关键知识有更加充分的讲解与体会。希望可以通过具体实例驱动课程进行。通过较为丰富的实例可以对与新知识有较为全面的认识与感知。通过实例来理解知识将有更加深刻印象,有助于之后使用于与长久记忆。希望作业加大对于知识综合性的应用,使得作业更加趋向于实际问题。最后希望在作业结束之后,对作业问题进行指导,有助于更好的进步,同时对于问题及解题思路的讲解也有助于之后问题的思考与当前作业所存在的缺陷进一步完善。
Java基础课程已经结束,但对于Java知识的学习与提升才刚刚开始。更熟练的使用Java,更好的类关系设计将作为之后学习的目标与方向。相较于Java宏大的知识体系,所学的知识不过风毛菱角,更加丰富的知识还尚未来到。要不断学习,不断探索,虚心学习,勤于练习。

浙公网安备 33010602011771号