题目集4~6总结
(1)前言:
题目集04:主要考查了类和对象间的联系,如何将不同类间相联系,实例化,继承,父类与子类的关系和基本概念。其中题目7-1难度较大,需对正则表达式由较高的掌握,7-2难度适中,7-3较简单,是继承的基础问题。
题目集05:题目7-1~7-3主要考察的知识点是对数组的运用,对数组的分割,排序,组合等功能的实现;题目7-4难度大,考察的是java集合框架;题目7-5是题目集04 7-2的第二个版本,其类图与之前不同,主要区别在于在不同的类中创建对象。
题目集06:题目量大但难度低,多为较基础的题目:正则表达式的基本运用、继承、多态和接口的运用。
(2)设计与分析:
题目集04 7-2 日期问题面向对象设计(聚合一) (35 分)
参考题目7-2的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
注意:严禁使用Java中提供的任何与日期相关的类与方法,并提交完整源码,包括主类及方法(已提供,不需修改)
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
- 1 year month day n //测试输入日期的下n天
- 2 year month day n //测试输入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
- 当输入有误时,输出格式如下: Wrong Format
- 当第一个数字为1且输入均有效,输出格式如下:
- year-month-day
- 当第一个数字为2且输入均有效,输出格式如下:
- year-month-day
- 当第一个数字为3且输入均有效,输出格式如下:
- 天数值
提交源码:
import java.util.Scanner;
class Date {
private int year;
private int month;
private int day;
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getDay() {
return day;
}
public int getMonth() {
return month;
}
public int getYear() {
return year;
}
public static boolean isLeapYear(int year) {//判断year是否为闰年,返回boolean类型;
boolean isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
return isLeapYear;
}
int[] DayOfMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public int getDaysOfMonth(int year, int month) {
int days;
days = DayOfMonth[month - 1];
if (isLeapYear(year) && month == 2) {
days = 29;
}
return days;
}
public boolean checkInputValidity()//判断输入日期是否合法,返回布尔值
{
boolean checkInputValidity = (year >= 1900 && year <= 2050) && (month <= 12 && month >= 1) && (day > 0 && day <= getDaysOfMonth(year,month));
return checkInputValidity;
}
public Date getNNextDays(int n) {
int year = this.year;
int month = this.month;
int day = this.day;
for (int i = 0; i < n; i++) {
day++;
if (day > getDaysOfMonth(year,month)) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
}
return new Date(year,month,day);
}
public Date getNPreviousDays(int n) {
int year = this.year;
int month = this.month;
int day = this.day;
for (int i = 0;i < n;i++){
day --;
if (day < 1) {
month --;
if (month < 1) {
year --;
month = 12;
}
day =day + getDaysOfMonth(year,month);
}
}
return new Date(year,month,day);
}
public String show(){
return year+"-"+month+"-"+day;
}
public int getDaysofDates(Date date,Date anotherDate) {
int numOfLeapYear = 0;
int days = 0;
Date littleDate= date;
Date largeDate = anotherDate;
if ((date.year > anotherDate.year) || ((date.year == anotherDate.year) && (date.month > anotherDate.month)) || ((date.year == anotherDate.year) && (date.month == anotherDate.month) && (date.day > anotherDate.day))){
largeDate = date;
littleDate = anotherDate;
}
for(int i = littleDate.getYear();i < largeDate.getYear();i ++){
if (isLeapYear(i)){
numOfLeapYear ++;
}
}
days = (largeDate.getDay() - littleDate.getDay()) + (DayOfMonth[largeDate.getMonth() - 1] - DayOfMonth[littleDate.getMonth() -1]) + (largeDate.getYear() - littleDate.getYear() - numOfLeapYear) * 365 + numOfLeapYear * 366;
return days;
}
}
public class Main{
public static void main(String[] args){
Scanner input = new Scanner(System.in);
int choice = input.nextInt();
if (choice != 1 && choice != 2 && choice != 3){
System.out.println("Wrong Format");
return;
}
switch (choice){
case 1:
int year1 = input.nextInt();
int month1 = input.nextInt();
int day1 = input.nextInt();
Date a = new Date(year1,month1,day1);
if(!a.checkInputValidity()){
System.out.println("Wrong Format");
return;
}
int n1 = input.nextInt();
if(n1 < 0) {
System.out.println("Wrong Format");
}
else {
System.out.println(a.getNNextDays(n1).show());;
}
break;
case 2:
int year2 = input.nextInt();
int month2 = input.nextInt();
int day2 = input.nextInt();
Date b = new Date(year2,month2,day2);
if (!b.checkInputValidity()){
System.out.println("Wrong Format");
return;
}
int n2 = input.nextInt();
if(n2 < 0) {
System.out.println("Wrong Format");
}
else {
System.out.println(b.getNPreviousDays(n2).show());;
}
break;
case 3:
int year3 = input.nextInt();
int month3 = input.nextInt();
int day3 = input.nextInt();
int year4 = input.nextInt();
int month4 = input.nextInt();
int day4 = input.nextInt();
int year5 = 0;
int month5 = 0;
int day5 = 0;
Date c = new Date(year3,month3,day3);
Date d = new Date(year4,month4,day4);
Date e = new Date(year5,month5,day5);
if(!c.checkInputValidity() || !d.checkInputValidity()){
System.out.println("Wrong Format");
return;
}
int days = e.getDaysofDates(c,d);
System.out.println(days);
}
}
}
由于当时对类与类之间的联系还不清楚,在编写代码过程中,编译器始终警告说我创建的对象为空,在看过老师发的正确代码后,发现应该是创建对象的时候没有一层一层创建,于是我为了应急实现功能就做成了一个类class Date()同样能够实现功能,但是功能3有一个测试点未能通过,原因是我的getDaysofDates()方法在处理带有闰年闰月时含有逻辑错误。例如:给到输入3 2002 7 27 2020 7 27,其输出结果应是6575,但输出结果却少了1:
这道题目需要注意的点有:在处理前两个功能时,要注意跨年、跨月、闰月等基本情况,这些情况不容易被忽视。而第三个功能则显得比较麻烦,因为要确定两个日期之间具体跨了多少个月——多少个闰月,小月,大月。尽管当时改进了,但还是存在瑕疵。
题目集05 7-5 日期问题面向对象设计(聚合二) (40 分)
参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:
与前者相比,可以发现这里的Year,Month,Day类时相互独立的,这与前者不同,前者属于Year,Month,Day,DateUtil四个类之间相互调用,而此题是直接在DateUtil类中调用其他三个类,这样做的优点是,代码相对简单,不需要很繁琐的循环调用,而前者的优点则是通过类之间的调用体现出了各类的关系,体现的更为清楚。
题目集04 7-3 图形继承 (15 分)
编写程序,实现图形类的继承,并定义相应类对象并进行测试。
- 类Shape,无属性,有一个返回0.0的求图形面积的公有方法public double getArea();//求图形面积
- 类Circle,继承自Shape,有一个私有实型的属性radius(半径),重写父类继承来的求面积方法,求圆的面积
- 类Rectangle,继承自Shape,有两个私有实型属性width和length,重写父类继承来的求面积方法,求矩形的面积
- 类Ball,继承自Circle,其属性从父类继承,重写父类求面积方法,求球表面积,此外,定义一求球体积的方法public double getVolume();//求球体积
- 类Box,继承自Rectangle,除从父类继承的属性外,再定义一个属性height,重写父类继承来的求面积方法,求立方体表面积,此外,定义一求立方体体积的方法public double getVolume();//求立方体体积
- 注意:
- 每个类均有构造方法,且构造方法内必须输出如下内容:Constructing 类名
- 每个类属性均为私有,且必须有getter和setter方法(可用Eclipse自动生成)
- 输出的数值均保留两位小数
主方法内,主要实现四个功能(1-4): 从键盘输入1,则定义圆类,从键盘输入圆的半径后,主要输出圆的面积; 从键盘输入2,则定义矩形类,从键盘输入矩形的宽和长后,主要输出矩形的面积; 从键盘输入3,则定义球类,从键盘输入球的半径后,主要输出球的表面积和体积; 从键盘输入4,则定义立方体类,从键盘输入立方体的宽、长和高度后,主要输出立方体的表面积和体积;
假如数据输入非法(包括圆、矩形、球及立方体对象的属性不大于0和输入选择值非1-4),系统输出Wrong Format
输入格式:
共四种合法输入
- 1 圆半径
- 2 矩形宽、长
- 3 球半径
- 4 立方体宽、长、高
输出格式:
按照以上需求提示依次输出
题目集06 7-5 图形继承与多态 (50 分)
掌握类的继承、多态性及其使用方法。具体需求参见作业指导书。
输入格式:
从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数),数与数之间可以用一个或多个空格或回车分隔。
输出格式:
- 如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边关系),则输出Wrong Format。
- 如果输入合法,则正常输出,输出内容如下(输出格式见输入输出示例):
- 各个图形的面积;
- 所有图形的面积总和;
- 排序后的各个图形面积;
- 再次所有图形的面积总和。
提交源码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
ArrayList<Double> areaList = new ArrayList<>();
// System.out.println("Please input the quantities of geo and the information:");
int numberOfCircle = input.nextInt();
int numberOfRectangle = input.nextInt();
int numberOfTriangle = input.nextInt();
if (numberOfCircle < 0 || numberOfRectangle < 0 || numberOfTriangle < 0){
System.out.println("Wrong Format");
return;
}
Circle[] circles = new Circle[numberOfCircle];
Rectangle[] rectangles = new Rectangle[numberOfRectangle];
Triangle[] triangles = new Triangle[numberOfTriangle];
int i;
for (i=0;i<numberOfCircle;i++){
double radius = input.nextDouble();
circles[i] = new Circle(radius);
if (!circles[i].validate()) {
System.out.println("Wrong Format");
return;
}
areaList.add(circles[i].getArea());
}
for (i=0;i<numberOfRectangle;i++){
double length = input.nextDouble();
double width = input.nextDouble();
rectangles[i] = new Rectangle(length,width);
if(!rectangles[i].validate()){
System.out.println("Wrong Format");
return;
}
areaList.add(rectangles[i].getArea());
}
for (i=0;i<numberOfTriangle;i++){
double a = input.nextDouble();
double b = input.nextDouble();
double c = input.nextDouble();
triangles[i] = new Triangle(a,b,c);
if(!triangles[i].validate()){
System.out.println("Wrong Format");
return;
}
areaList.add(triangles[i].getArea());
}
System.out.println("Original area:");
double sumArea = 0;
for (i=0;i<numberOfCircle + numberOfRectangle + numberOfTriangle;i++){
System.out.printf("%.2f ",areaList.get(i));
sumArea = sumArea + areaList.get(i);
}
System.out.println();
System.out.print("Sum of area:");
System.out.printf("%.2f",sumArea);
System.out.println();
System.out.println("Sorted area:");
int j;
for (i=0;i<areaList.size();i++){
for (j=0;j<areaList.size()-i-1;j++){
if (areaList.get(j+1) < areaList.get(j)) {
Double temp = areaList.get(j);
areaList.set(j,areaList.get(j+1));
areaList.set(j+1,temp);
}
}
}
for (i=0;i<areaList.size();i++) {
System.out.printf("%.2f ",areaList.get(i));
}
System.out.println();
System.out.print("Sum of area:");
System.out.printf("%.2f",sumArea);
}
}
abstract class Shape {
public abstract double getArea();
public abstract boolean validate();
public abstract String show();
}
class Circle extends Shape {
double radius;
public Circle(double radius) {
super();
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 show() {
return String.format("%.2f"+getArea()) + " ";
}
}
class Rectangle extends Shape {
double length,width;
public Rectangle(double length,double width) {
super();
this.width = width;
this.length = length;
}
@Override
public double getArea() {
return length * width;
}
@Override
public boolean validate() {
if (this.length <= 0 || this.width <= 0)
return false;
else
return true;
}
@Override
public String show() {
return String.format("%.2f"+getArea()) + " ";
}
}
class Triangle extends Shape{
double a,b,c;
public Triangle(double a,double b,double c) {
super();
this.a = a;
this.b = b;
this.c = c;
}
@Override
public double getArea() {
return Math.sqrt((a+b+c)*(a+b-c)*(a+c-b)*(b+c-a))/4;
}
@Override
public boolean validate() {
if ((this.a <= 0 || this.b <=0 || this.c <= 0) || ((this.a + this.b) <= this.c) || ((this.a + this.c) <= this.b) || ((this.b + this.c) <= this.a))
return false;
else
return true;
}
@Override
public String show() {
return String.format("%.2f"+getArea()) + " ";
}
}
题目集06 7-6 实现图形接口及多态性 (30 分)
编写程序,使用接口及类实现多态性,类图结构如下所示:
其中:
- GetArea为一个接口,无属性,只有一个GetArea(求面积)的抽象方法;
- Circle及Rectangle分别为圆类及矩形类,分别实现GetArea接口
- 要求:在Main类的主方法中分别定义一个圆类对象及矩形类对象(其属性值由键盘输入),使用接口的引用分别调用圆类对象及矩形类对象的求面积的方法,直接输出两个图形的面积值。(要求只保留两位小数)
输入格式:
从键盘分别输入圆的半径值及矩形的宽、长的值,用空格分开。
输出格式:
- 如果输入的圆的半径值及矩形的宽、长的值非法(≤0),则输出Wrong Format
- 如果输入合法,则分别输出圆的面积和矩形的面积值(各占一行),保留两位小数。
提交源码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Circle c = new Circle();
Rectangle r = new Rectangle();
double radius,width,length;
radius = input.nextDouble();
width = input.nextDouble();
length = input.nextDouble();
c.setRadius(radius);
r.setLength(length);
r.setWidth(width);
if (radius <= 0 || width <= 0 || length <= 0) {
System.out.println("Wrong Format");
}
else {
System.out.println(String.format("%.2f",c.getArea()));
System.out.println(String.format("%.2f",r.getArea()));
}
}
}
interface GetArea {
double getArea();
}
class Circle implements GetArea {
private double radius;
public Circle() {
}
public Circle(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
class Rectangle implements GetArea {
private double length;
private double width;
public Rectangle() {
}
public Rectangle(double length,double width) {
this.length = length;
this.width = width;
}
public double getLength() {
return length;
}
public void setLength(double length) {
this.length = length;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
@Override
public double getArea() {
return length * width;
}
}
题目集04 7-3是属于较为基础的继承例题,通过定义一个Shape类为父类并定义一个getArea方法,让子类通过关键字extends继承。由于每种图形的面积求法并不相同,因此需要在子类中重写getArea方法。而一些立体图形具有与平面图形相同的属性(如:Ball与Circle),则Ball可直接继承CIrcle,这样做的好处是不需要重写getArea方法,而是直接用super关键字调用即可。
题目集06 7-5则较为综合,考察了ArrayList类的用法,抽象类、抽象方法、抽象类定义、实体类构建的运用。需要清楚的是,抽象类里的抽象方法无法被实例化,而在该题目中,每种图形都有自己的面积,但其getArea并不相同,因此getArea应定义为抽象方法,validate同理。而对ArrayList使用冒泡排序,也是需要注意将变量定义为对应类型,使用get.访问成员等ArrayList方法。
题目集06 7-6要求使用接口,接口为特殊类,考察了类与接口间的相连——通过关键字implements
题目集06 7-1、7-3~7-4,考察的是基本的正则表达式,正则表达式匹配数字、字母,总结如下:
英文字母:[a-zA-Z],数字:[0-9],长度{x,y},|表示或,每部分用()区分。
(3)踩坑心得:
1、计算两日期相差多少天时,考虑的不够周全,我一开始考虑的是将年份先循环,if(isLeapYear),numsOfLeapYear++;这样得到了闰年的数量,也就得到了平年的数量,再想用月数相减,日期相减,看似能得出差值,但因为不确定相差的几个月各有多少天,所以无法求得准确值。
2、在主方法中,如果不用访问器setter将输入的值传给各属性,那么即便输入了结果也都是0.00,

(4)改进建议:
应充分利用多类调用的便捷性,不仅能使代码量减少,也使代码具有层次感,更美观,
而将其全部聚集在一个类里写虽然可行,但可读性较低,不利于改进,
(5)总结:通过这三次题目,我学习了ArrayList的基础知识,正则表达式的基本运用,对类与类之间的相互调用更加熟练,感受了封装、多态的优点所在,除此之外,也对之前学习的排序方法,字符串、保留小数位数进行了复习。

浙公网安备 33010602011771号