目录
前言
经过了几周的java学习,初步了解到java与c语言的不同:C语言是一门面向过程、抽象化的通用程序设计语言;Java是一门面向对象编程语言,Java语言是从C语言衍生而来,它吸收了C语言的许多优点,并且摒弃了C中难以理解的多继承、指针等概念。
题目集01:
- 主要考察基本数据类型的使用,简单的逻辑分析,数据的输入输出处理等能力
- 题目集题量较大,难度较易
题目集02:
- 主要考察字符串处理能力以及简单类的使用
- 题目集题量较少,难度一般
题目集03:
- 主要考察简单类的设计和使用以及类图的功能实现
- 题目集题量较少,难度偏高
设计与分析
题目集01
7-6 学号识别
学校的学号由8位数字组成,前两位是入学年份(省略了20);第3、4位是学院编号,01代表材料学院,02代表机械学院,03代表外语学院,20代表软件学院;第5、6位是学院内部班级编号,最后两位是班级内部学号。如:18011103,入学年份是2018年,材料学院,11班,03号
输入格式:
8位数字组成的学号。例如:18011103
注意:输入学号不是8位或者学院编号不是01、02、03、20其中之一,属于非法输入
输出格式:
学号每一项的完整说明。例如:
入学年份:2018年
学院:材料学院
班级:11
学号:03
注意:如非法输入,输出“Wrong Format"
code
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
String stuNumber;
Scanner input=new Scanner(System.in);
stuNumber=input.nextLine();
if((stuNumber.length()==8)&&((stuNumber.substring(2,4).equals("01"))||(stuNumber.substring(2,4).equals("02"))||(stuNumber.substring(2,4).equals("03"))||(stuNumber.substring(2,4).equals("20"))))
{
System.out.println("入学年份:20"+stuNumber.substring(0,2)+"年");
if(stuNumber.substring(2,4).equals("01"))
{
System.out.println("学院:材料学院");
}
else if(stuNumber.substring(2,4).equals("02"))
{
System.out.println("学院:机械学院");
}
else if(stuNumber.substring(2,4).equals("03"))
{
System.out.println("学院:外语学院");
}
else if(stuNumber.substring(2,4).equals("20"))
{
System.out.println("学院:软件学院");
}
System.out.println("班级:"+stuNumber.substring(4,6));
System.out.println("学号:"+stuNumber.substring(6,8));
}
else{
System.out.println("Wrong Format");
}
}
}
在这个程序中使用了String类中的获取子字符串的方法 substring(beginIndex,endIndex)
,方法s.charAt(index)
虽然可以用于提取字符串s中的单个特定字符,但是在学号识别中每两位数字都代表不同的信息,使用单个字符不便于对其整体分析,或会使代码变的比较复杂。在方法substring(beginIndex,endIndex)
中需要注意的是位于endIndex
位置的字符不属于该子字符串的一部分,所以在获取目标子字符串时应该对于最后的下标加一以及需要保证beginIndex < endIndex
,如果beginIndex = endIndex
将会返回一个长度为0的空字符串,如果beginIndex > endIndex
将发生运行时错误。
题目集 02
7-1 字母数字转换
输入一个由英文字母组成的字符串(大小写均可),将所有英文字母转换成它们在字母表中的序号,例如:“AbbcD”转换为“12234”。
输入格式:
由英文字母组成的字符串(大小写均可)。例如:“AbbcD”
若包含非英文字母,视为非法输入。
输出格式:
所有英文字母转换成它们在字母表中的序号,例如:“12234”。
非法输入输出"Wrong Format".
code
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String s=input.nextLine();
s=s.toUpperCase();
boolean flag=true;
for(int i=0;i<s.length();i++) {
if(s.charAt(i)>='A'&&s.charAt(i)<='Z') {
flag = true;
}
else {
flag = false;
break;
}
}
if(flag) {
for(int i=0;i<s.length();i++)
System.out.print(s.charAt(i)-'A'+1);
}
else {
System.out.print("Wrong Format");
}
}
}
分析该题目要求 输入一个由英文字母组成的字符串(大小写均可),将所有英文字母转换成它们在字母表中的序号 因为英文字母在字母表中的位置不会因为大小写变换,所以在程序中使用了toUpperCase()
方法 ,该方法可以返回所有字母为大写的新字符串,同样也可以使用toLowerCase()
方法转换为小写字母达到同样目的,这样处理可以简化判断的流程,降低复杂度,避免简单错误的发生。
SourceMonitor的生成报表内容
可以看出代码的平均复杂度较高,但是最大复杂度不高,相比于未使用toUpperCase()
方法,代码的复杂度略有降低。
7-2 串口字符解析
RS232是串口常用的通信协议,在异步通信模式下,串口可以一次发送5~8位数据,收发双方之间没有数据发送时线路维持高电平,相当于接收方持续收到数据“1”(称为空闲位),发送方有数据发送时,会在有效数据(5~8位,具体位数由通信双方提前设置)前加上1位起始位“0”,在有效数据之后加上1位可选的奇偶校验位和1位结束位“1”。请编写程序,模拟串口接收处理程序,注:假定有效数据是8位,奇偶校验位采用奇校验。
输入格式:
由0、1组成的二进制数据流。例如:11110111010111111001001101111111011111111101111
输出格式:
过滤掉空闲、起始、结束以及奇偶校验位之后的数据,数据之前加上序号和英文冒号。
如有多个数据,每个数据单独一行显示。
若数据不足11位或者输入数据全1没有起始位,则输出"null data",
若某个数据的结束符不为1,则输出“validate error”。
若某个数据奇偶校验错误,则输出“parity check error”。
若数据结束符和奇偶校验均不合格,输出“validate error”。
如:11011或11111111111111111。
例如:
1:11101011
2:01001101
3:validate error
code
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
String temp=null;
Scanner input = new Scanner (System.in);
String s = input.nextLine();
boolean flag=false;//判断输入数据是否合法
boolean right=false;
int count=1,sum=0,num;//count为序号 sum记录奇数个数
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='0'){
flag=true;
break;
}
}
if(s.length()<11||flag==false){
System.out.println("null data");
}
else{//如果数据输入合法
for(int j=0;j<s.length();j++)
{
if(s.charAt(j)=='0'){//如果出现起始位
sum=0;
for(int i=1;i<9;i++){
if(((int)s.charAt(j+i))%2==1){
sum++;
}
}
if(s.charAt(10+j)!='1'){
System.out.println(count+":validate error");
count++;
j+=10;
}
else if(sum%2!=0&&s.charAt(9+j)!='0'){
System.out.println(count+":parity check error");
count++;
j+=10;
}
else if(sum%2==0&&s.charAt(9+j)!='1'){
System.out.println(count+":parity check error");
count++;
j+=10;
}
else {
System.out.println(count+":"+s.substring(j+1,j+9));
count++;
j+=10;
}
}
}
}
}
}
由题意可知收发双方之间没有数据发送时线路维持高电平,相当于接收方持续收到数据“1”所以采用循环对字符串进行遍历来判断是否出现了起始位,如果出现了起始位“0”,在使用循环判断数据是否有效,主要在于字符串的处理和考虑问题的全面性。
SourceMonitor的生成报表内容
SourceMonitor 分析可知,代码的质量不高,函数深度以及复杂度都较高,原因在于在学习c语言和JAVA的过渡过程中,习惯于使用IPO的方式来处理简单程序问题,在后续的改进和学习过程中,会更加偏重于JAVA的编程风格。
题目集03
7-1 用类解二元一次方程
定义一个代表一元二次方程ax2+bx+c=0的类QuadraticEquation,其属性为三个系数a、b、c(均为私有属性)
输入格式:
在一行中输入a、b、c的值,可以用一个或多个空格或回车符分开。
输出格式:
- 当输入非法时,输出“Wrong Format”
- 当有一个实根时,输出(2行):
- a=值,b=值,c=值:
- The root is 值(保留两位小数)
- 当有两个实根时,输出(2行):
- a=值,b=值,c=值:
- The roots are 值1 and 值2(均保留两位小数)
code
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner input = new Scanner(System.in);
double a = Double.parseDouble(input.next());
double b = Double.parseDouble(input.next());
double c = Double.parseDouble(input.next());
if(a == 0){
System.out.println("Wrong Format");
System.exit(0);
}
//create a QuadraticEquation object
QuadraticEquation equation = new QuadraticEquation(a, b, c);
//get value of b * b - 4 * a * c
double discriminant = equation.getDiscriminant();
System.out.println("a=" + equation.getA() +
",b=" + equation.getB() +
",c=" + equation.getC()+":");
if (discriminant < 0) {
System.out.println("The equation has no roots.");
}
else if (discriminant == 0)
{
System.out.println("The root is " +
String.format("%.2f", equation.getRoot1()));
}
else // (discriminant >= 0)
{
System.out.println("The roots are " +
String.format("%.2f", equation.getRoot1())
+ " and " + String.format("%.2f", equation.getRoot2()));
}
}
}
class QuadraticEquation{
private double a,b,c,root1,root2;
public QuadraticEquation() {
super();
// TODO 自动生成的构造函数存根
}
public QuadraticEquation(double a1,double b1,double c1) {
this.a = a1;
this.b = b1;
this.c = c1;
}
public double getA(){
return this.a;
}
public double getB(){
return this.b;
}
public double getC(){
return this.c;
}
public double getDiscriminant() {
double delta;
delta = this.b*this.b-4*this.a*this.c;
return delta;
}
public double getRoot1() {
double ca1,ca2;
ca1 = -(this.b/(2*this.a));
ca2 = (Math.sqrt(this.b*this.b-4*this.a*this.c))/(2*this.a);
this.root1 = ca1 + ca2;
return this.root1;
}
public double getRoot2() {
double ca1,ca2;
ca1 = -(this.b/(2*this.a));
ca2 = (Math.sqrt(this.b*this.b-4*this.a*this.c))/(2*this.a);
this.root1 = ca1 + ca2;
this.root2 = ca1 - ca2;
return this.root2;
}
}
题目要求使用类来解二元一次方程,所以关键在于简单类的设计和使用 在QuadraticEquation
类中有两个构造方法,一个是有参的构造方法,一个是无参的构造方法,构造方法是用来实现类的实例化(创建对象) 类是泛指,而对象是特指,无参和有参的构造方法区别在于实例化对象的同时有没有对属性进行初始化,在方法中实现了求二元一次方程的数学公式程序化,但是在主类中需要考虑方程根的情况,后续还要进行改进。
SourceMonitor 生成报表内容 PowerDesigner 生成类图
根据 SourceMonitor 生成报表内容分析可知在使用类来解决二元一次方程后,函数的深度和复杂度都在合格的范围内,所以在编写JAVA程序应适当的使用类。
根据PowerDesigner 生成类图分析可知 主类和QuadraticEquation
类的关系为依赖,类之间的耦合度较低。
7-2 日期类设计
参考题目集二中和日期相关的程序,设计一个类DateUtil,该类有三个私有属性year、month、day(均为整型数),其中,year∈[1820,2020] ,month∈[1,12] ,day∈[1,31] , 除了创建该类的构造方法、属性的getter及setter方法外,需要编写如下方法:
public boolean checkInputValidity();//检测输入的年、月、日是否合法
public boolean isLeapYear(int year);//判断year是否为闰年
public DateUtil getNextNDays(int n);//取得year-month-day的下n天日期
public DateUtil getPreviousNDays(int n);//取得year-month-day的前n天日期
public boolean compareDates(DateUtil date);//比较当前日期与date的大小(先后)
public boolean equalTwoDates(DateUtil date);//判断两个日期是否相等
public int getDaysofDates(DateUtil date);//求当前日期与date之间相差的天数
public String showDate();//以“year-month-day”格式返回日期值
应用程序共测试三个功能:
- 求下n天
- 求前n天
- 求两个日期相差的天数
输入格式:
有三种输入方式(以输入的第一个数字划分[1,3]):
- 1 year month day n //测试输入日期的下n天
- 2 year month day n //测试输入日期的前n天
- 3 year1 month1 day1 year2 month2 day2 //测试两个日期之间相差的天数
输出格式:
- 当输入有误时,输出格式如下:
Wrong Format
- 当第一个数字为1且输入均有效,输出格式如下:
year1-month1-day1 next n days is:year2-month2-day2
- 当第一个数字为2且输入均有效,输出格式如下:
year1-month1-day1 previous n days is:year2-month2-day2
- 当第一个数字为3且输入均有效,输出格式如下:
The days between year1-month1-day1 and year2-month2-day2 are:值
code
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int year = 0;
int month = 0;
int day = 0;
int choice = input.nextInt();
if (choice == 1) { // test getNextNDays method
int m = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
m = input.nextInt();
if (m < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " next " + m + " days is:");
System.out.println(date.getNextNDays(m).showDate());
} else if (choice == 2) { // test getPreviousNDays method
int n = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
n = input.nextInt();
if (n < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(
date.getYear() + "-" + date.getMonth() + "-" + date.getDay() + " previous " + n + " days is:");
System.out.println(date.getPreviousNDays(n).showDate());
} else if (choice == 3) { // test getDaysofDates method
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
int anotherYear = Integer.parseInt(input.next());
int anotherMonth = Integer.parseInt(input.next());
int anotherDay = Integer.parseInt(input.next());
DateUtil fromDate = new DateUtil(year, month, day);
DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
System.out.println("The days between " + fromDate.showDate() + " and " + toDate.showDate() + " are:"
+ fromDate.getDaysofDates(toDate));
} else {
System.out.println("Wrong Format");
System.exit(0);
}
} else {
System.out.println("Wrong Format");
System.exit(0);
}
}
}
class DateUtil {
private int year, month, day;
public DateUtil() {
super();
// TODO 自动生成的构造函数存根
}
public DateUtil(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return this.year;
}
public int getMonth() {
return this.month;
}
public int getDay() {
return this.day;
}
public boolean checkInputValidity() {
boolean flag = true;
if (year < 1820 || year > 2020 || month < 1 || month > 12 || day < 1 || day > 31) {
flag = false;
} else {
if (!isLeapYear(year) && month == 2 && day >= 29)// 平年2月大于等于29天
{
flag = false;
} else if (isLeapYear(year) && month == 2 && day > 29)// 闰年2月大于29天
{
flag = false;
} else if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10
|| month == 12) && day > 31) {
flag = false;
} else if ((month == 4 || month == 6 || month == 9 || month == 11) && day > 30) {
flag = false;
} else
flag = true;
}
return flag;// 检测输入的年、月、日是否合法
}
public boolean isLeapYear(int year) {
boolean isleap = ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
return isleap;// 判断year是否为闰年
}
public DateUtil getNextNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.isLeapYear(year) && month <= 2) {
if (month == 2 && day == 29) {
day = 1;
month = 3;
}
year++;
n = n - 366;
} else if (this.isLeapYear(year + 1) && month > 2) {
year++;
n = n - 366;
} else {
year++;
n = n - 365;
}
}
for (int i = 0; i < n; i++) {
day++;
if (this.isLeapYear(year) && month == 2) {
if (day > 29) {
month++;
day = 1;
}
} else if (day > months[month]) {
month++;
day = 1;
if (month > 12) {
month = 1;
year++;
}
}
}
DateUtil nextDate = new DateUtil(year, month, day);
return nextDate;
}
public DateUtil getPreviousNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.isLeapYear(year) && month > 2) {
n -= 366;
year--;
} else if (this.isLeapYear(year - 1) && month <= 2) {
n -= 366;
year--;
} else {
n -= 365;
year--;
}
}
for (int i = 0; i < n; i++) {
day--;
if (day <= 0) {
month--;
if (month <= 0) {
month = 12;
year--;
}
if (isLeapYear(year) && month == 2)
day = 29;
else
day = months[month];
}
}
DateUtil nextDate = new DateUtil(year, month, day);
return nextDate;
}
public boolean compareDates(DateUtil date) {
boolean flag = false;
if (date.getYear() < year)
flag = true;
else if (date.getYear() > year)
flag = false;
else {
if (date.getMonth() < month)
flag = true;
else if (date.getMonth() > month)
flag = false;
else {
if (date.getDay() < day)
flag = true;
else if (date.getDay() > day)
flag = false;
}
}
return flag;// 比较当前日期与date的大小(先后)
}
public boolean equalTwoDates(DateUtil date) {
if (date.getYear() != year || date.getMonth() != month || date.getDay() != day)
return false;
else
return true;// 判断两个日期是否相等
}
public int getDaysofDates(DateUtil date)// 求当前日期与date之间相差的天数
{
int count = numOfDays(year, month, day) - numOfDays(date.getYear(), date.getMonth(), date.getDay());
if (count < 0)
count = -count;
return count;
}
public int numOfDays(int year, int month, int day)
// 求出year-month-day到0001-1-1的距离天数,返回整型数;
{
int sum = 0;
for (int i = 1; i < year; i++) {
if (isLeapYear(i) == true)
sum += 366;
else
sum += 365;
}
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
for (int i = 1; i < month; i++) {
if (i == 2 && isLeapYear(year) == true)
sum++;
sum += months[i];
}
sum += day;
return sum;
}
public String showDate() {
String s = "", x = "", y = "", z = "";
x = "" + this.year;
y = "" + this.month;
z = "" + this.day;
s = x + "-" + y + "-" + z;
return s;// 以“year-month-day”格式返回日期值
}
}
该程序需要设计一个DateUtil类来处理日期变换的问题,难点在于闰年与平年时日期变换需要进行不同的处理,所以应该判断是否为闰年再进行相应的处理,对于两个日期相差的天数,可以利用numOfDays
计算出两个日期相距同一天的天数再相减。
SourceMonitor 生成报表内容 PowerDesigner 生成类图
根据 SourceMonitor 生成报表内容分析可知程序的复杂度较高,但是深度在正常范围。
根据PowerDesigner 生成类图分析可知 主类和类的关系为依赖,DateUtil
类之间的耦合度较低。
7-3 日期问题面向对象设计(聚合一)
参考题目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且输入均有效,输出格式如下:
天数值
code
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int year = 0, month = 0, day = 0, m, n;
int choice = input.nextInt();//判断操作类型
year = input.nextInt();
month = input.nextInt();
day = input.nextInt();
DateUtil date = new DateUtil(year, month, day);
if (choice == 1) {
n = input.nextInt();// 输入n
if (!date.checkInputValidity() || n < 0) {// 如果数据不合法
System.out.println("Wrong Format");
System.exit(0);
} else
System.out.println(date.getNextNDays(n).showDate());
} else if (choice == 2) {
m = input.nextInt();// 输入m
if (!date.checkInputValidity() || m< 0) {// 如果数据不合法
System.out.println("Wrong Format");
System.exit(0);
} else
System.out.println(date.getPreviousNDays(m).showDate());
} else if (choice == 3) {
int anotherYear = Integer.parseInt(input.next());
int anotherMonth = Integer.parseInt(input.next());
int anotherDay = Integer.parseInt(input.next());
DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
if (!date.checkInputValidity() || !toDate.checkInputValidity()) {// 如果数据不合法
System.out.println("Wrong Format");
System.exit(0);
} else
System.out.println(date.getDaysofDates(toDate));
} else
System.out.println("Wrong Format");
}
}
class Year {
private int value;
public Year() {
super();
// TODO 自动生成的构造函数存根
}
public Year(int value) {
super();
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public boolean isLeapYear() {
boolean flag =false;
if ((value % 4 == 0 && value % 100 != 0) || value % 400 == 0)
flag = true;
return flag;
}
public boolean validate() {
if (value <= 2050 && value >= 1900)
return true;
else
return false;
}
public void yearIncrement() {
value++;
}
public void yearReduction() {
value--;
}
}
class Month {
private int value;
private Year year;
public Month() {
super();
// TODO 自动生成的构造函数存根
}
public Month(int yearValue, int monthValue) {
this.year = new Year(yearValue);
this.value = monthValue;
}
public int getValue() {
return value;
}
public Year getYear() {
return year;
}
public void setValue(int value) {
this.value = value;
}
public void setYear(Year year) {
this.year = year;
}
public void resetMin() {
this.value = 1;
}
public void resetMax() {
this.value = 12;
}
public boolean validate() {
if (value >= 1 && value <= 12)
return true;
else
return false;
}
public void monthIncrement() {
value ++;
}
public void monthReduction() {
value --;
}
}
class Day {
private int value;
private Month month;
private int[] mon_maxnum1 = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
public Day() {
super();
// TODO 自动生成的构造函数存根
}
public Day(int yearValue, int monthValue, int dayValue) {
this.month = new Month(yearValue, monthValue);
this.value = dayValue;
}
public int getValue() {
return value;
}
public Month getMonth() {
return month;
}
public void setValue(int value) {
this.value = value;
}
public void setMonth(Month month) {
this.month = month;
}
public void resetMin() {
value = 1;
}
public void resetMax() {
value = mon_maxnum1[month.getValue() - 1];
}
public boolean validate() {
if (this.getMonth().getYear().isLeapYear())
mon_maxnum1[1] = 29;
if (value >= 1 && value <= mon_maxnum1[month.getValue() - 1])
return true;
else
return false;
}
public void dayIncrement() {
value ++;
}
public void dayReduction() {
value --;;
}
}
class DateUtil {
private Day day;
public DateUtil() {
super();
// TODO 自动生成的构造函数存根
}
public DateUtil(int d, int m, int y) {
this.day = new Day(d, m, y);
}
public Day getDay() {
return day;
}
public void setDay(Day day) {
this.day = day;
}
public boolean checkInputValidity() {
if (!this.getDay().getMonth().getYear().validate() || !this.getDay().getMonth().validate() ) return false;
else if(!day.validate())return false;
return true;
}
public boolean compareDates(DateUtil date) {
boolean flag = false;
if (date.getDay().getMonth().getYear().getValue() < this.getDay().getMonth().getYear().getValue())
flag = true;
else if (date.getDay().getMonth().getYear().getValue() >this.getDay().getMonth().getYear().getValue())
flag = false;
else {
if (date.getDay().getMonth().getValue() < this.getDay().getMonth().getValue())
flag = true;
else if (date.getDay().getMonth().getValue() >this.getDay().getMonth().getValue())
flag = false;
else {
if (date.getDay().getValue() < this.getDay().getValue())
flag = true;
else if (date.getDay().getValue() > this.getDay().getValue())
flag = false;
}
}
return flag;
}
public boolean equalTwoDates(DateUtil date) {
if (date.getDay().getMonth().getYear().getValue() != this.getDay().getMonth().getYear().getValue()
|| date.getDay().getMonth().getValue() != this.getDay().getMonth().getValue()
|| date.getDay().getValue() != this.getDay().getValue())
return false;
else
return true;
}
public String showDate() {
String s = "", x = "", y = "", z = "";
x = "" + this.getDay().getMonth().getYear().getValue();
y = "" + this.getDay().getMonth().getValue();
z = "" + this.getDay().getValue();
s = x + "-" + y + "-" + z;
return s;// 以“year-month-day”格式返回日期值
}
public DateUtil getNextNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.getDay().getMonth().getYear().isLeapYear()
&& this.getDay().getMonth().getValue() <= 2) {
if (this.getDay().getMonth().getValue() == 2 && this.day.getValue() == 29) {
this.getDay().setValue(1);
this.getDay().getMonth().setValue(3);
}
this.getDay().getMonth().getYear().yearIncrement();
n = n - 366;
} else if (this.getDay().getMonth().getYear().isLeapYear()
&& this.getDay().getMonth().getValue() > 2) {
this.getDay().getMonth().getYear().yearIncrement();
n = n - 366;
} else {
this.getDay().getMonth().getYear().yearIncrement();
n = n - 365;
}
}
for (int i = 0; i < n; i++) {
this.getDay().dayIncrement();
if (this.getDay().getMonth().getYear().isLeapYear()
&& this.getDay().getMonth().getValue() == 2) {
if (this.getDay().getValue() > 29) {
this.getDay().getMonth().monthIncrement();
this.getDay().setValue(1);
}
} else if (this.getDay().getValue() > months[this.getDay().getMonth().getValue()]) {
this.getDay().getMonth().monthIncrement();
this.getDay().setValue(1);
if (this.getDay().getMonth().getValue() > 12) {
this.getDay().getMonth().setValue(1);
this.getDay().getMonth().getYear().yearIncrement();
}
}
}
DateUtil nextDate = new DateUtil(this.getDay().getMonth().getYear().getValue(), this.getDay().getMonth().getValue(),
this.getDay().getValue());
return nextDate;
}
public DateUtil getPreviousNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.getDay().getMonth().getYear().isLeapYear()
&& this.getDay().getMonth().getValue() > 2) {
n -= 366;
this.getDay().getMonth().getYear().yearReduction();
} else if (this.getDay().getMonth().getYear().isLeapYear()
&& this.getDay().getMonth().getValue() <= 2) {
n -= 366;
this.getDay().getMonth().getYear().yearReduction();
} else {
n -= 365;
this.getDay().getMonth().getYear().yearReduction();
}
}
for (int i = 0; i < n; i++) {
this.getDay().dayReduction();
if (this.getDay().getValue() <= 0) {
this.getDay().getMonth().monthReduction();
if (this.getDay().getMonth().getValue() <= 0) {
this.getDay().getMonth().setValue(12);
this.getDay().getMonth().getYear().yearReduction();
}
if (this.getDay().getMonth().getYear().isLeapYear()
&& this.getDay().getMonth().getValue() == 2)
this.getDay().setValue(29);
else
this.getDay().setValue(months[this.getDay().getMonth().getValue()]);
}
}
DateUtil nextDate = new DateUtil(this.getDay().getMonth().getYear().getValue(), this.getDay().getMonth().getValue(),
this.getDay().getValue());
return nextDate;
}
public int getDaysofDates(DateUtil date)// 求当前日期与date之间相差的天数
{
int count = numOfDays(this.getDay().getMonth().getYear().getValue(),this.getDay().getMonth().getValue(),this.getDay().getValue())
- numOfDays(date.getDay().getMonth().getYear().getValue(), date.getDay().getMonth().getValue(),
date.getDay().getValue());
if (count < 0)
count = -count;
return count;
}
public int numOfDays(int year, int month, int day)
// 求出year-month-day到0001-1-1的距离天数,返回整型数;
{
int sum = 0;
for (int i = 1; i < year; i++) {
if (i % 4 == 0 && i % 100 != 0 || (i % 400 == 0))
sum += 366;
else
sum += 365;
}
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
for (int i = 1; i < month; i++) {
if (i == 2 && year % 4 == 0 && year % 100 != 0 || (year % 400 == 0))
sum++;
sum += months[i];
}
sum += day;
return sum;
}
}
本题要求根据类图实现功能,给出的类图就像是我们的客户我们要完全按照客户的要求去实现,不能改变类的方法,类的名称,甚至是私有属性的名称。
SourceMonitor 生成报表内容
根据 SourceMonitor 生成报表内容分析可知程序的平均的复杂度较低,但是最大复杂度仍较高,但是深度在正常范围。
7-4 日期问题面向对象设计(聚合二)
参考题目7-3的要求,设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1820,2020] ,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且输入均有效,输出格式如下:
year1-month1-day1 next n days is:year2-month2-day2
- 当第一个数字为2且输入均有效,输出格式如下:
year1-month1-day1 previous n days is:year2-month2-day2
- 当第一个数字为3且输入均有效,输出格式如下:
The days between year1-month1-day1 and year2-month2-day2 are:值
code
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int year = 0;
int month = 0;
int day = 0;
int choice = input.nextInt();
if (choice == 1) { // test getNextNDays method
int m = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
m = input.nextInt();
if (m < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(date.getYear().getValue() + "-" + date.getMonth().getValue() + "-" + date.getDay().getValue() + " next " + m + " days is:");
System.out.println(date.getNextNDays(m).showDate());
} else if (choice == 2) { // test getPreviousNDays method
int n = 0;
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
DateUtil date = new DateUtil(year, month, day);
if (!date.checkInputValidity()) {
System.out.println("Wrong Format");
System.exit(0);
}
n = input.nextInt();
if (n < 0) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.print(
date.getYear().getValue() + "-" + date.getMonth().getValue() + "-" + date.getDay().getValue() + " previous " + n + " days is:");
System.out.println(date.getPreviousNDays(n).showDate());
} else if (choice == 3) { //test getDaysofDates method
year = Integer.parseInt(input.next());
month = Integer.parseInt(input.next());
day = Integer.parseInt(input.next());
int anotherYear = Integer.parseInt(input.next());
int anotherMonth = Integer.parseInt(input.next());
int anotherDay = Integer.parseInt(input.next());
DateUtil fromDate = new DateUtil(year, month, day);
DateUtil toDate = new DateUtil(anotherYear, anotherMonth, anotherDay);
if (fromDate.checkInputValidity() && toDate.checkInputValidity()) {
System.out.println("The days between " + fromDate.showDate() +
" and " + toDate.showDate() + " are:"
+ fromDate.getDaysofDates(toDate));
} else {
System.out.println("Wrong Format");
System.exit(0);
}
}
else{
System.out.println("Wrong Format");
System.exit(0);
}
}
}
class Year {
private int value;
public Year() {
super();
// TODO 自动生成的构造函数存根
}
public Year(int value) {
super();
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public boolean isLeapYear() {
boolean flag =false;
if ((value % 4 == 0 && value % 100 != 0) || value % 400 == 0)
flag = true;
return flag;
}
public boolean validate() {
if (value <= 2020 && value >= 1820)
return true;
else
return false;
}
public void yearIncrement() {
value++;
}
public void yearReduction() {
value--;
}
}
class Month {
private int value;
public Month() {
super();
// TODO 自动生成的构造函数存根
}
public Month(int value) {
super();
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public void resetMin() {
this.value = 1;
}
public void resetMax() {
this.value = 12;
}
public boolean validate() {
if (value >= 1 && value <= 12)
return true;
else
return false;
}
public void monthIncrement() {
value ++;
}
public void monthReduction() {
value --;
}
}
class Day {
private int value;
public Day() {
super();
// TODO 自动生成的构造函数存根
}
public Day(int value) {
super();
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
// public void resetMin() {
// value = 1;
// }
//
// public void resetMax() {
// value = mon_maxnum1[month.getValue() - 1];
// }
// public boolean validate() {
// if (this.getMonth().getYear().isLeapYear())
// mon_maxnum1[1] = 29;
// if (value >= 1 && value <= mon_maxnum1[month.getValue() - 1])
// return true;
// else
// return false;
// }
public void dayIncrement() {
value ++;
}
public void dayReduction() {
value --;;
}
}
class DateUtil {
private Day day = new Day();
private Month month= new Month();
private Year year= new Year();
private int[] mon_maxnum1 = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
public DateUtil() {
super();
// TODO 自动生成的构造函数存根
}
public DateUtil(int y, int m, int d) {
day.setValue(d);
month.setValue(m);
year.setValue(y);
}
public Day getDay() {
return day;
}
public void setDay(Day day) {
this.day = day;
}
public Month getMonth() {
return month;
}
public void setMonth(Month month) {
this.month = month;
}
public Year getYear() {
return year;
}
public void setYear(Year year) {
this.year = year;
}
public boolean checkInputValidity() {
if (!this.year.validate() || !this.month.validate() ) return false;
else {
if (this.year.isLeapYear()) mon_maxnum1[1] = 29;
if (day.getValue() >= 1 && day.getValue() <= mon_maxnum1[month.getValue() - 1]) return true;
else return false;
}
}
public boolean compareDates(DateUtil date) {
boolean flag = false;
if (date.year.getValue() < this.year.getValue())
flag = true;
else if (date.year.getValue() >this.year.getValue())
flag = false;
else {
if (date.month.getValue() < this.month.getValue())
flag = true;
else if (date.month.getValue() >this.month.getValue())
flag = false;
else {
if (date.day.getValue() < this.day.getValue())
flag = true;
else if (date.day.getValue() > this.day.getValue())
flag = false;
}
}
return flag;
}
public boolean equalTwoDates(DateUtil date) {
if (date.year.getValue() != this.year.getValue()
|| date.month.getValue() != this.month.getValue()
|| date.day.getValue() != this.day.getValue())
return false;
else
return true;
}
public String showDate() {
String s = "", x = "", y = "", z = "";
x = "" + this.year.getValue();
y = "" + this.month.getValue();
z = "" + this.day.getValue();
s = x + "-" + y + "-" + z;
return s;// 以“year-month-day”格式返回日期值
}
public DateUtil getNextNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.year.isLeapYear()
&& this.month.getValue() <= 2) {
if (this.month.getValue() == 2 && this.day.getValue() == 29) {
this.getDay().setValue(1);
this.month.setValue(3);
}
this.year.yearIncrement();
n = n - 366;
} else if (this.year.isLeapYear()
&& this.month.getValue() > 2) {
this.year.yearIncrement();
n = n - 366;
} else {
this.year.yearIncrement();
n = n - 365;
}
}
for (int i = 0; i < n; i++) {
this.getDay().dayIncrement();
if (this.year.isLeapYear()
&& this.month.getValue() == 2) {
if (this.day.getValue() > 29) {
this.month.monthIncrement();
this.getDay().setValue(1);
}
} else if (this.day.getValue() > months[this.month.getValue()]) {
this.month.monthIncrement();
this.getDay().setValue(1);
if (this.month.getValue() > 12) {
this.month.setValue(1);
this.year.yearIncrement();
}
}
}
DateUtil nextDate = new DateUtil(this.year.getValue(), this.month.getValue(),
this.day.getValue());
return nextDate;
}
public DateUtil getPreviousNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.year.isLeapYear()
&& this.month.getValue() > 2) {
n -= 366;
this.year.yearReduction();
} else if (this.year.isLeapYear()
&& this.month.getValue() <= 2) {
n -= 366;
this.year.yearReduction();
} else {
n -= 365;
this.year.yearReduction();
}
}
for (int i = 0; i < n; i++) {
this.getDay().dayReduction();
if (this.day.getValue() <= 0) {
this.month.monthReduction();
if (this.month.getValue() <= 0) {
this.month.setValue(12);
this.year.yearReduction();
}
if (this.year.isLeapYear()
&& this.month.getValue() == 2)
this.getDay().setValue(29);
else
this.getDay().setValue(months[this.month.getValue()]);
}
}
DateUtil nextDate = new DateUtil(this.year.getValue(), this.month.getValue(),
this.day.getValue());
return nextDate;
}
public int getDaysofDates(DateUtil date)// 求当前日期与date之间相差的天数
{
int count = numOfDays(this.year.getValue(),this.month.getValue(),this.day.getValue())
- numOfDays(date.year.getValue(), date.month.getValue(),date.day.getValue());
if (count < 0)
count = -count;
return count;
}
public int numOfDays(int year, int month, int day)
// 求出year-month-day到0001-1-1的距离天数,返回整型数;
{
int sum = 0;
for (int i = 1; i < year; i++) {
if (i % 4 == 0 && i % 100 != 0 || (i % 400 == 0))
sum += 366;
else
sum += 365;
}
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
for (int i = 1; i < month; i++) {
if (i == 2 && year % 4 == 0 && year % 100 != 0 || (year % 400 == 0))
sum++;
sum += months[i];
}
sum += day;
return sum;
}
}
本题与上题一样根据类图来实现功能,与上题不同的是类之间的关系不同,相比于7-3 这个程序类之间的耦合度更小 类与类之间联系更少。
SourceMonitor 生成报表内容
根据 SourceMonitor 生成报表内容分析类的数量更少 ,平均复杂度也降低了一点,但是最大复杂度仍然较高。
采坑心得
题目集01
7-6 学号识别
问题1:使用String类中的方法substring(beginIndex,endIndex)
不知道它返回的子字符串是从指定位置beginIndex
的字符开始一直到下标为endIndex-1
的字符结束。
解决方案:对于目标返回的子字符串的结束下标后移一位。
题目集02
7-2 串口字符解析
问题1:输出的控制条件逻辑不清晰,导致测试点不能通过
解决方案:更改输出控制条件以保证能判断特殊情况
原控制条件:
更改为:
题目集03
7-1 用类解二元一次方程
本题中未出现问题,但是需要注意的是输出格式的方法,在本题中学到了可以使用String类中的 String.format()
方法进行常规类型的格式化输出,类似于c中的printf()
,使用该方法,我们可以控制输出的小数的整数部分个数以及小数点后面的个数。
7-2 日期类设计
问题1: 前n天与后n天计算均出现错误
问题分析:前面n天与后n天均出现问题 可能是判断条件出现问题,或者计算逻辑问题,对于该题目的日期计算 出于方便的想法 直接复制了题目集二中的计算逻辑,后面发现在题目集二中的日期计算问题对于该题并不适用,题目集二中的前n天和后n天 的 n 的值有所限制 不会出现很大的值,但是对于本题,n的值可能会出现较大的值,这也就导致了本题中的逻辑错误。
解决方案:更换计算逻辑
原逻辑code
public DateUtil getPreviousNDays(int n) {
if ((month == 12 || month == 5 || month == 7 || month == 10) && day - n < 0) {
month--;
day = 30 - (n - day);
} else if ((month == 2 || month == 4 || month == 6 || month == 9 || month == 11 || month == 8) && day - n < 0) {
month--;
day = 31 - (n - day);
} else if (!isLeapYear(year) && month == 3) {
month--;
day = 28 - (n - day);
} else if (isLeapYear(year) && month == 3) {
month--;
day = 29 - (n - day);
} else if (month == 1 && day - n < 0) {
year--;
month = 12;
day = 31 - (n - day);
} else {
day -= n;
} // 取得year-month-day的前n天日期
DateUtil nextDate = new DateUtil(year, month, day);
return nextDate;
}
更换逻辑代码
public DateUtil getNextNDays(int n) {
int[] months = new int[] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
while (n > 365) {
if (this.isLeapYear(year) && month <= 2) {
if (month == 2 && day == 29) {
day = 1;
month = 3;
}
year++;
n = n - 366;
} else if (this.isLeapYear(year + 1) && month > 2) {
year++;
n = n - 366;
} else {
year++;
n = n - 365;
}
}
for (int i = 0; i < n; i++) {
day++;
if (this.isLeapYear(year) && month == 2) {
if (day > 29) {
month++;
day = 1;
}
} else if (day > months[month]) {
month++;
day = 1;
if (month > 12) {
month = 1;
year++;
}
}
}
DateUtil nextDate = new DateUtil(year, month, day);
return nextDate;
}
7-3 日期问题面向对象设计(聚合一)
问题1:日期越界
问题分析: 未考虑题目给出的边界值 导致测试点的日期超界问题
解决方案:更换日期边界值
问题2: 未完全按照类图来设计类和实现类
问题分析: 由于不知道如何在public int getDaysofDates(DateUtil date)
方法中实现该方法功能,所以采取了public int numOfDays(int year, int month, int day)
的方法折中处理,但是更改了类图,不符合题目要求,所以在后续的改进过程中应保证程序和已给出类图的完全吻合。
解决方案:在public int getDaysofDates(DateUtil date)
中独立实现方法功能。
改进建议
题目集02
- 在自己对方法或者类命名时并不能完全做到见名知意,对于方法名、参数名、成员变量、局部变量都统一使用lowerCamelCase风格,类名使用UpperCamelCase风格,必须遵从驼峰形式,常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
- 为了达到代码自解释的目标,任何自定义编程元素在命名时,应使用尽量完整的单词组合来表达其意,不要为了减短名字长度而强行缩写导致的望文不知意。
- 代码格式不够规范 对于大括号的使用 以及缩进的使用不规范,没有必要增加若干空格来使某一行的字符与上一行对应位置的字符对齐,在变量比较多的情况下,是一种累赘的事情。
题目集03
- 在根据类图实现功能时,应保证与类图的吻合度,不能擅自改变,减少或添加方法或常量等。
- 整体结构比较复杂的程序,在实现之前可以画出类图和流程图来实现,以保证逻辑的严密性。
总结
学习总结:
在经过了几周的JAVA学习,对JAVA这门语言有了一个初步的认识,JAVA是一门面向对象编程语言,Java语言是从C语言衍生而来,它吸收了C语言的许多优点,并且摒弃了C中难以理解的多继承、指针等概念。在这几次的题目集主要学习到了一些简单类的使用和类之间的关系,通过合理的使用一些简单类的方法,可以降低代码的复杂度。通过题目集三 了解到类之间有那些关系 ,类之间有六种关系:关联,继承,泛化,实现,依赖,以及聚合在设计类的时候,我们应该尽量做到类和类之间的耦合度低 ,即遵守迪米特法则(迪米特法则又叫做最少知道原则,就是说一个对象应当对其它对象有尽可能少的了解,不要和陌生人说话。 强调只和朋友说话,不和陌生人说话。这里的朋友指的是:出现在成员变量,方法输入,输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。 迪米特法则初衷在于降低类之间的耦合。由于每个类尽量减少对其它类的依赖,因此。很容易使得系统的功能模块独立,相互之间不存在(或很少有)依赖关系)从而提高了类的可复用率和系统的扩展性,但是过度使用迪米特法则会使系统产生大量的中介类,从而增加系统的复杂性,使模块之间的通信效率降低。所以,在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。所以在后续的学习过程中,要学会如何根据特定的环境去衡量使用迪米特法则以提高自身代码质量,同时要刻意保持与现在的流行的规范的代码格式一致,培养自己的规范意识。比如学习阿里的规范格式,避免在后续工作的过程中去强行改变而不适应。对于类图的使用才刚刚接触,但是发现在设计一个较大的程序应提前画图(流程图和类图等),一个清晰的代码逻辑对于实现代码功能有很大的好处,比如在后续的题目集中,如果不画好流程图,抬手就写代码往往不能保证代码质量。
教学建议:
在几周的学习过程中认为教学的方式比较好,希望在后续的学习过程中能与社会中的实际需求相接触,对较老的教学点适当改进,以保证与社会的接轨。