PTA题目集4-6总结
PTA题目集4-6总结
一:前言
在题集4-6中,所考查的主要知识点有正则表达式,类与类之间的调用,类的聚合,继承,封装,接口与多态,三种排序方法如选择排序,冒泡排序,插入排序,ArrayList,stringbuilder和集合的使用等。题量一般,题目难度从第一次的比较难,然后难度逐渐降低,中间偶尔有穿插几个对于我来说有点难度的题目,但是学习了一些我认为比之前更高级一点的知识。
二:设计与分析
(1):题目集4(7-2)& 题目集五(7-5):
这两题主要考查了类与类之间的调用和聚合。
7-2:参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下

在7-2中,运用了类的多层调用,如在月类中调用了年类,在日期类中调用了月类,在DateUtil中又调用了日期类,一层一层的嵌套和调用实现了日期的聚合。开始时对于日期和DAteUtil类调用月类和日期类时,没有理解到位,在传入参数时没有传全,只传入了一个参数,后发现有的数据无法传入因此发现问题。
private Year year; public Month(int year,int value) { this.value = value; this.year = new Year(year); }
public Day(int year,int month,int value) { this.month = new Month(year,month); this.value = value; }
public DateUtil(int y,int m,int d) { this.day=new Day(y,m,d); }
优点:该种聚合对计算日期的前N天或后N天的代码较为简单,在年月日中都对前一方进行调用和计算,在最后的DateUtil类中只需要调用前面类中的方法即可,如对前N天和后N天的代码如下,十分简洁:
public DateUtil getNextDays(int n) { for(int i=0;i<n;i++) { day.dayIncrement(); } return new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); } public DateUtil getPerviousDays(int n) { for(int i=0;i<n;i++) { day.dayReduction(); } return new DateUtil(day.getMonth().getYear().getValue(),day.getMonth().getValue(),day.getValue()); }
缺点:该种聚合方法嵌套太多,太过麻烦,而且通过每一级的一级一级调用,如果一处出了问题后面将都会出错,且不太容易找到错误所在。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
7-5:参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
在7-5的聚合方法中,有了前面7-2的经验,所碰到的问题也少了许多,在7-5中与7-2不同的是,在7-5中年月日类中并没有相互调用,而是在DateUtil类中直接对前面三者年月日类进行总的调用,在7-2中可以在前面写好日期的增加和减少的方法后面自己调用即可,而现在则只能在DateUtil类完善对日期的前N天和后N天的计算代码。如后N天的代码:
public DateUtil getNextDays(int n) { for(int i=0;i<n;i++) { if(year.isLeapYear()) { mon_maxnum[1]=29; } else { mon_maxnum[1]=28; } if(month.getValue()==12&&day.getValue()==mon_maxnum[month.getValue()-1]) { year.yearIncrement(); setDayMin(); month.resetMin(); } else if(day.getValue()==mon_maxnum[month.getValue()-1]){ month.monthIncrement(); setDayMin(); } else day.dayIncrement(); } return new DateUtil(year.getValue(),month.getValue(),day.getValue()); }
使用这种聚合设计避免了多层嵌套,而且较为主要的算法都在DateUtil类中,较为容易的找到问题所在,思路也更加清晰。
(2):题集4(7-3)& 题集6(7-5)& 题集6(7-6)
7-3:图形继承
编写程序,实现图形类的继承,并定义相应类对象并进行测试
思路:首先有父类Shape,其中有一个求面积的公共方法
class Shape{ private double radius; Shape(){ System.out.println("Constructing Shape"); } public Shape(double radius) { this.radius=radius; } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } }
后写子类Circle类,他继承自Shape,并且有一个半径属性,然后重写父类继承来的求面积的方法;
class Circle extends Shape{ private double radius; Circle(){ System.out.println("Constructing Circle"); } public Circle(double radius) { this.radius = radius; } public double getArea() { return radius*radius*Math.PI; } }
再写Rectangle类,与Circle类相似,他继承自Shape,有两个私有属性长度和宽度,然后重写父类继承来的求面积的方法;
class Rectangle extends Shape{ private double width; private double length; Rectangle(){ System.out.println("Constructing Rectangle"); } public Rectangle(double width, double length) { this.width = width; this.length = length; } public double getArea() { return width*length; } }
再写Ball类,他继承自Circle类,其半径属性也是从父类Circle继承,然后重写父类求面积的方法来求表面积,另外再增加一个方法来求球的体积;
class Ball extends Circle{ public Ball() { System.out.println("Constructing Ball"); } public Ball(double radius) { setRadius(radius); } public double getSurfaceArea() { return 4.0*getRadius()*getRadius()*Math.PI; } public double getVolume() { return (4.0/3.0)*Math.pow(getRadius(), 3)*Math.PI; } }
最后写Box类,他继承自Rectangle类,其长度和宽度属性从父类继承,另外再增加一个高度属性,重写父类继承来的求面积方法,求立 方体表面积,此外再增加一个方法来求立方体的体积。
class Box extends Rectangle{ double height; public Box() { System.out.println("Constructing Box"); } public Box(int height) { this.height = height; } public Box(double width, double length,double height) { setWidth(width); setLength(length); this.height=height; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public double getSurfaceArea() { return (getWidth()*getLength()+getWidth()*height+getLength()*height)*2; } public double getVolume(){ return getLength()*getWidth()*height; } }

7-6: 实现图形接口及多态性

由题目所给类图可知,有两个类Circle类,Rectangle类和一个求面积GetArea的接口,接口无属性,只有一个GetArea(求面积)的抽象方法;
interface Area{ public abstract double getArea(); }
后面两个类分别实现求面积接口,并重写求面积的方法;
class Circle implements Area{ double radius; public Circle(double radius) { this.radius = radius; } Circle(){} public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } @Override public double getArea() { System.out.printf("%.2f\n",Math.PI*radius*radius); return 0; } } class Rectangle implements Area{ double width; double length; Rectangle(){} public Rectangle(double width, double length) { this.width = width; this.length = length; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } public double getLength() { return length; } public void setLength(double length) { this.length = length; } @Override public double getArea() { System.out.printf("%.2f",width*length); return 0; } }
7-5 图形继承与多态:
思路:首先有三个图形类分别为Circle,Rectangle,Triangle,然后从他们中可以抽象出一个形状类,其中里面有求面积,判断数据是否合法和输出面积信息的抽象方法,因此可以先写抽象类Shape,里面有·三个抽象方法,然后Circle,Rectangle,Triangle这三个类都继承自抽象类Shape,三个类都要实现抽象类中的所有抽象方法,因此在三个类中再重写抽象类中的方法
abstract class Shape { public abstract double getArea(); public abstract boolean validate(); public abstract String toString(); } //圆 class Circle extends Shape { double radius; public Circle(double radius) { // super(); this.radius = radius; } Circle() { } public double getRadius() { return radius; } public void setRadius(double radius) { this.radius = radius; } @Override public double getArea() { return Math.PI * radius * radius; } @Override public boolean validate() { if (radius <= 0) return false; else return true; } @Override public String toString() { // TODO Auto-generated method stub return null; } } //矩形 class Rectangle extends Shape { double width; double length; Rectangle() { } public Rectangle(double width, double length) { super(); this.width = width; this.length = length; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } public double getLength() { return length; } public void setLength(double length) { this.length = length; } @Override public double getArea() { return width * length; } @Override public boolean validate() { if (width <=0 | length <= 0) return false; else return true; } @Override public String toString() { // TODO Auto-generated method stub return null; } } //三角形 class Triangle extends Shape { double side1; double side2; double side3; Triangle() { } public Triangle(double side1, double side2, double side3) { // super(); this.side1 = side1; this.side2 = side2; this.side3 = side3; } public double getSide1() { return side1; } public void setSide1(double side1) { this.side1 = side1; } public double getSide2() { return side2; } public void setSide2(double side2) { this.side2 = side2; } public double getSide3() { return side3; } public void setSide3(double side3) { this.side3 = side3; } @Override public double getArea() { // TODO Auto-generated method stub double i = (side1 + side2 + side3) / 2.0; return Math.sqrt(i * (i - side1) * (i - side2) * (i - side3)); } @Override public boolean validate() { // TODO Auto-generated method stub double[] side = { side1, side2, side3 }; Arrays.sort(side); if (side1 <= 0 | side2 <= 0 | side3 <= 0 | side[0] + side[1] <= side[2] | side[2] - side[1] >= side[0]) return false; else return true; } @Override public String toString() { // TODO Auto-generated method stub return null; } }
因为三个对象的数量不确定,可能有多个,所以将他们创建的各个图形对象均存储在 ArrayList类型的列表中可以更好操作,然后将三个子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法,然后使用add方法向集合添加对象
ArrayList<Shape> list = new ArrayList<>(); for (int i = 0; i < a; i++) { double radius = in.nextDouble(); Shape circle = new Circle(radius); list.add(circle); } for (int i = 0; i < b; i++) { double width = in.nextDouble(); double length = in.nextDouble(); Shape rectangle = new Rectangle(width, length); list.add(rectangle); } for (int i = 0; i < c; i++) { double side1 = in.nextDouble(); double side2 = in.nextDouble(); double side3 = in.nextDouble(); Shape triangle = new Triangle(side1, side2, side3); list.add(triangle); }
类图:

(3)正则表达式
1: matches()用于检测字符串是否匹配给定的正则表达式;
2:split()用于分割字符;
3:Pattern 对象是正则表达式编译后在内存中的表示形式,因此,正则表达式字符串必须先被编译为 Pattern 对象,然后再利用该 Pattern 对象创建对应的 Matcher 对象,如:
// 将一个字符串编译成 Pattern 对象 Pattern p1 = Pattern.compile(".*?(//.*)"); // 使用 Pattern 对象创建 Matcher 对象 Matcher m1 = p1.matcher(s);
4:Matcher 类提供了几个常用方法,如find():返回目标字符串中是否包含与Patter匹配的子串;group():返回上一次与Pattern匹配的子串
5:StringBuilder 类是代表可变字符串类,它提供了 append 和 add 方法,可以将字符串添加到已有序列的末尾或指定位置
if (m1.find()) { s = s.replace(m1.group(1), " "); strbuild.append(s + " "); }
6:trim(),用于删除字符串的头尾空白符
for(int i=0;i<5;i++) { b[i]=b[i].trim(); }
(4)题目集5(7-4)中Java集合框架应用的分析总结
Map用于保存具有映射关系的数据,Map集合里保存着两组值,一组用于保存Map的key,另一组保存着Map的value,通过key找到对应的value
Map中的常用方法:
- Object get():返回指定key对应的value,如果不包含key则返回null;
- Object put(Objeect key,Object value):添加一个键值对,如果集合中的key重复,则覆盖原来的键值对;
void clear():删除该Map对象中所有键值对;int size():返回该Map里的键值对个数;Object remove(Object key):删除指定的key对应的键值对,并返回被删除键值对的value,如果不存在,则返回null;Set keySet():返回Map中所有key组成的集合;
三:踩坑心得
1:对参数的传递和理解还有函数的调用还有待加强;
2:nextLine()吸取字符前后的空格/Tab键,回车键截止,next()不会吸取字符前/后的空格/Tab键,只吸取字符,开始吸取字符(字符前后不算)直到遇到空格/Tab键/回车截止吸取,一开始用的时候没有考虑到直接使用的next(),导致数组越界错误;
3:对数据的格式输出不够规范和仔细,比较粗心;
四:改进建议
在求日期问题当中求两个日期相隔多少天中,类图中所给的是方法比较两个日期的大小,然后再判断是否相等,通过日期的运算达到相等来求之间相隔的天数,我认为这样写比较麻烦而且当出错时不容易找到错误所在,因此我通过设置最小日期的年月日为第一天,通过计算他们之间两个日期到最小日期的天数相减即为两个日期相差天数;
五:总结
1:对正则表达式有了更深的理解,并且对他的运用也更加熟练,但是这部分还是比较模糊,需要多学习和练习;
2:学了ArrayList,能将对象放入一个数组,运用更加方便,灵活;
3:学会了类的聚合,继承,接口,多态等以及对类与类之间的调用有了更清晰的认识和应用;
4:对于排序的各种写法更加熟练;
5:学习了新的知识集合框架,重点学习了一下Map集合的各种运用,但是不太会使用,并且java的集合框架有挺多的还没有学完,要多花点时间将这一块学完学懂;

浙公网安备 33010602011771号