初学javaPTA前三次作业集总结
一.前言
1)第一次题目集其中涉及内容包括循环结构的建立,数组的运用以及java的基本程序设计的基础内容(包括Java中对数据的输入输出的规则,以及对赋值变量的运用)和对s.indexOf(b)==s.lastIndexOf(b)、str.charAt()的应用。其中第十题由于掺入了对GPS的数据处理规律,故在理解上对我存在较大难度;在对第七题的编译中,找不到如何能实现的方法,故认为难度较大;至于其他题目难度都较低,在有部分C语言的语法基础下也能顺利完成,但题量较大有利于对java基础编程方法上更熟练。
2)第二次作业的题目涉及内容主要还是在对if语句的设立以及在对三角形的性质和日期类问题的介入,题量较大在熟悉java基础编程后这次题目集无疑在我们逻辑上的训练有很大的帮助,其中第8题的判断三角形帮助我们锻炼了各类情况的判断以及对输入数据在之后运算中的精度范围的意识,由于是老师自主命题,具有一定难度;第九题引入了java中对日期的设定问题,初次在java函数设定上有了训练,同时对日期中年(是否为闰),月日中2月的特殊性以及30与31的不同;
3)第三次作业集其中涉及内容实现了升级,包括了对class的引用以及在对import java.time.LocalDate;的使用,对类中set()与get()的涉及与运用方法,包括对privata的个人信息的界定以及对其中数据的调取;其中第二题中的LoacalData得运用介绍了同时存入年月日的方式,有助于思维的扩展;第三题与第四题难度较大,在对日期的设定及判断上做出了升级,不仅是基础的日期问题,同时要求我们对类中数据调用以及设立方法有一定自己的思考与见解,特别第四题在对方法的建立上更为负责,特别锻炼编程思维;
二.设计与分析
1.有重复的数据(第一次作业第七题)
这题从表面看似是简单的数组的遍历问题,但实际上如若对一大堆的数据没有定义,存在超时的问题,但我的代码却存在答案错误的问题;
我的源码:
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); int n=in.nextInt(); String str=in.nextLine(); String sa=""; for(int i=0;i<str.length();i++) { char b=str.charAt(i); if(str.charAt(i)==' ') { sa+=b; } else{ if(str.indexOf(b)==str.lastIndexOf(b)) { sa+=b; } else{ if(str.indexOf(b)==i) { sa+=b; } } } } int x=str.length(); int y=sa.length(); if(x==y){ System.out.println("NO"); } else{ System.out.println("YES"); } } }

改进方法:感觉可以使用两边同时向中间查找或者二分法去解决问题;
2.定义日期类(第三次作业)
本题是关于对日期的各项问题的测试,在第二次题目集的最后一题这道也与日期类相关的题目里,我使用了对年月日分别定义的方式去实现代码,但是会出现代码过长的现象,而后在老师的提及下才发现这些繁而杂的代码会被认定为垃圾代码。好在老师在课上提到可以以设立数组的形式去实现对月日的表达,我才发现原来代码表达可以如此多变了,关键在我们自身的思考;

源码实现:
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); int year=in.nextInt(); int month=in.nextInt(); int day=in.nextInt(); Date date=new Date(); date.setYear(year); date.setMonth(month); date.setDay(day); if(date.checkInputValidity()==true){ System.out.println("Date Format is Wrong"); } else{ date.getNextDate(); } } } class Date{ private int year; private int month; private int day; int[] mon={0,31,28,31,30,31,30,31,31,30,31,30,31}; public int getYear(){ return year; } public void setYear(int year){ this.year=year; } public int getMonth(){ return month; } public void setMonth(int month){ this.month=month; } public int getDay(){ return day; } public void setDay(int day){ this.day=day; } public static boolean isLeapYear(int year){ if(year%4==0){ if(year%100==0){ if(year%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } } public boolean checkInputValidity(){ if(this.year<1900||this.year>2000||this.month<1||this.month>12||this.day<1||this.day>31){ return true; } else if(isLeapYear(this.year)==true&&this.month==2&&this.day>29){ return true; } else if(isLeapYear(this.year)==false&&this.month==2&&this.day>28){ return true; } else{ return false; } } public void getNextDate(){ if(isLeapYear(this.year)==true){ mon[2]=29; } if(this.day==mon[this.month]){ this.day=1; if(this.month==12){ this.year+=1; this.month=1; } else{ this.month+=1; } } else{ this.day+=1; } System.out.println("Next day is:"+this.year+"-"+this.month+"-"+this.day); } }
源码在source Mointor中分析可得其复杂度以及深度:



同时可以得到基维亚图和块直方图:

以下为定义月份及其各月的代码:
int[] mon={0,31,28,31,30,31,30,31,31,30,31,30,31};
当然显而易见的可以发现2月份天数在其中被确定为了28天,故我们要在每一次的年份更新(包括第一次定义)都要去根据是否闰年去改2月的总日数,判断闰年代码如下:
public static boolean isLeapYear(int year){ if(year%4==0){ if(year%100==0){ if(year%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } }
更改数组内数据代码如下:
if(isLeapYear(this.year)==true){ mon[2]=29; }
再提出几点在设计代码时的易疏忽点:1.忘了判断年份是否未闰年;2.在当day达到月的最后一天后,要进行对day的归一和month的加一;3.当为一年中最后一天后年份要加一;4.在判断对日期设立是否合理是忘了2月下day的取值的不同;
3.日期设计类(第三次作业)
本题其实为第三次作业的日期设计题有异曲同工之处,可以说是对上一题的延伸和升级版;在这题中对类的调用更加复杂繁杂了,在解决该题时可谓是绞尽脑汁,在对多处错误的修改后才实现了基本功能;该题目类的方法有很多包括:
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天的方法创立中我出现了很多细节上的问题。在对当前日期与data之间相差天数上两个对象之间的差算法;
源码如下:
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; private int month; private int day; int[] mon={0,31,28,31,30,31,30,31,31,30,31,30,31}; public DateUtil(DateUtil d){ this.year=d.getYear(); this.month=d.getMonth(); this.day=d.getDay(); } public DateUtil(int x,int y,int z){ year=x; month=y; day=z; } public int getYear(){ return year; } public void setYear(int year){ this.year=year; } public int getMonth(){ return month; } public void setMonth(int month){ this.month=month; } public int getDay(){ return day; } public void setDay(int day){ this.day=day; } public static boolean isLeapYear(int year){ if(year%4==0){ if(year%100==0){ if(year%400==0){ return true; } else{ return false; } } else{ return true; } } else{ return false; } } public boolean checkInputValidity(){ if(this.year<1820||this.year>2020||this.month<1||this.month>12||this.day<1||this.day>31){ return false; } else if(isLeapYear(this.year)==true&&this.month==2&&this.day>29){ return false; } else if(isLeapYear(this.year)==false&&this.month==2&&this.day>28){ return false; } else{ return true; } } public DateUtil getNextNDays(int n){ while(n>365) { if(this.isLeapYear(this.year)==true&&this.month<=2){ n=n-366; this.year+=1; } else if(this.isLeapYear(this.year+1)==true&&this.month>2){ n=n-366; this.year+=1; } else{ n=n-365; this.year+=1; } } if(isLeapYear(this.year)==true){ mon[2]=29; } if((n-mon[this.month]+this.day-1)>=0){ n=n-mon[this.month]+this.day-1; this.day=1; this.month+=1; if(this.month>12){ this.month=1; this.year+=1; } while(n>=mon[this.month]){ if(isLeapYear(this.year)==true){ mon[2]=29; } n-=mon[this.month]; this.month+=1; if(this.month==13){ this.month=1; this.year+=1; } } this.day=n+1; } else{ this.day+=n; } return this; } public DateUtil getPreviousNDays(int n){ while(n>365) { if(this.isLeapYear(this.year)==true&&this.month>2){ n=n-366; this.year-=1; } else if(this.isLeapYear(this.year-1)==true&&this.month<=2){ n=n-366; this.year-=1; } else{ n=n-365; this.year-=1; } } if(isLeapYear(this.year)==true){ mon[2]=29; } if(n-this.day+1>=0){ n=n-this.day+1; this.day=1; this.month-=1; if(this.month<1){ this.month=12; this.year-=1; } while(n>=mon[this.month]){ if(isLeapYear(this.year)==true){ mon[2]=29; } n-=mon[this.month]; this.month-=1; if(this.month==0){ this.month=12; this.year-=1; } } this.day=mon[this.month]-n+1; } else { this.day-=n; } return this; } public boolean equalTwoDates(DateUtil date){ if(date.getDay()==this.day&date.getYear()==this.year&&date.getMonth()==this.month){ return true; } else{ return false; } } public boolean compareDates(DateUtil date){ if(equalTwoDates(date)==false){ if(date.getYear()>this.year){ return true; } else if(date.getYear()==this.year&&date.getMonth()>this.month){ return true; } else if(date.getYear()==this.year&&date.getMonth()==this.month&&date.getDay()>this.day){ return true; } else{ return false; } } else{ return false; } } public int getDaysofDates(DateUtil date){ int cha=0; if(equalTwoDates(date)==true){ return 0; } if(this.compareDates(date)==false){ while(this.year-date.getYear() >= 2){ if(this.isLeapYear(this.year) && this.month > 2) cha=cha+366; else if(this.isLeapYear(this.year-1) && this.month <= 2) cha= cha+366; else cha= cha+365; this.setYear(this.year - 1); } while(true){ if(this.equalTwoDates(date)) break; cha++; this.day-=1; if(this.day <= 0){ this.month-=1; if(this.month<= 0){ this.month=12; this.year-=1; } if(isLeapYear(this.year)&&this.month == 2) this.day=29; else this.day=this.mon[this.month]; } } } else if(this.compareDates(date)==true){ while(true){ if(this.equalTwoDates(date)) break; cha++; this.day+=1; if(isLeapYear(this.year)&&this.month==2){ if((this.day)>29){ this.month+=1; this.day=1; } } else if(this.day> this.mon[this.month]){ this.month+=1; this.day=1; if(this.month>12){ this.month=1; this.year+=1; } } } } return cha; } public String showDate(){ return year+"-"+month+"-"+day; } }
源码在source Mointor中分析可得其复杂度以及深度:


同时可以得到基维亚图和块直方图:

由于前后n天方法思路都大相径庭,故只对后n天出现问题分析:
1.首先便是面对n的赋值较大的情况下,开始几次的自我调试中总会出现运行超时的问题,在多次尝试后发现可以通过while语句来减小n的取值,同时要考虑month是否大于2与是否为闰年的问题:
while(n>365) { if(this.isLeapYear(this.year)==true&&this.month<=2){//区分年份差366与365的不同情况; n=n-366; this.year+=1; } else if(this.isLeapYear(this.year+1)==true&&this.month>2){ n=n-366; this.year+=1; } else{ n=n-365; this.year+=1; } }
我由于忘了对缩小n后的年份进行判断闰年从而导致一直出现nextday与perviousday的最大取值出现问题,故在上段代码后切莫忘记加上:
if(isLeapYear(this.year)==true){//判断是否为闰年; mon[2]=29; }
真的是细节决定成败啊!!!
2.在对日期推断的过程中,我的思路是去先进原本的day改变为1,n同时变化,然后进行月变化之后在进行日变化,最终得到结果:
if((n-mon[this.month]+this.day-1)>=0){//判断是否n大于实现让day化为下个月1号的取值; n=n-mon[this.month]+this.day-1; this.day=1; this.month+=1; if(this.month>12){ this.month=1; this.year+=1; } while(n>=mon[this.month]){ if(isLeapYear(this.year)==true){//年份改变后判断是否为闰年; mon[2]=29; }
else{
mon[2]=28;
} n-=mon[this.month]; this.month+=1; if(this.month==13){ this.month=1; this.year+=1; } } this.day=n+1; } else{//当n+day后不会超过当月总日时; this.day+=n; }
但是该方法其实也可借助for循环的方式去实现,对n的递减,通过与上一题中后一天的推导方式重复的运算,也能得出结果,但我认为while语句的执行速度应该会比for循环更快,实用型更高;
3.在对两日期间断之间我们还要判断前后,故我们要设立方法去判断其中两者的大小;
public boolean compareDates(DateUtil date){ if(equalTwoDates(date)==false){ if(date.getYear()>this.year){ return true; } else if(date.getYear()==this.year&&date.getMonth()>this.month){ return true; } else if(date.getYear()==this.year&&date.getMonth()==this.month&&date.getDay()>this.day){ return true; } else{ return false; } } else{ return false; } }
4.在对最后一直方法的创建下,认为是有必要借助其他方法以达到简便的效果;
辅助方法为下:
public DateUtil(DateUtil d){ this.year=d.getYear(); this.month=d.getMonth(); this.day=d.getDay(); }
通过此方式去实现两个不同日期的运算,由于日期的特殊性,故我认为计算方式可恶通过一动一静的方式去实现;因此我们要判断那个日期早那个日期短以决定那个日期去动,那个日期不动:
以前输入的日期小于后输入的日期为例,首要还是对年之间的差值,从大单位到小单位的运算:
int cha=0; if(equalTwoDates(date)==true){ return 0; } else if(this.compareDates(date)==false){ while(this.year-date.getYear() >= 2){ if(this.isLeapYear(this.year) && this.month > 2) cha=cha+366; else if(this.isLeapYear(this.year-1) && this.month <= 2) cha= cha+366; else cha= cha+365; this.setYear(this.year - 1); } while(true){ if(this.equalTwoDates(date)) break; cha++; this.day-=1; if(this.day <= 0){ this.month-=1; if(this.month<= 0){ this.month=12; this.year-=1; } if(isLeapYear(this.year)&&this.month == 2) this.day=29; else this.day=this.mon[this.month]; } } }
当时不知道存在对象数组的问题,但现在了解到该属性,估计以此方法能让思路更加清晰;
4.判断三角形类型(第二次作业集)
原题:
输入三角形三条边,判断该三角形为什么类型的三角形。
输入格式:
在一行中输入三角形的三条边的值(实型数),可以用一个或多个空格或回车分隔,其中三条边的取值范围均为[1,200]。
输出格式:
(1)如果输入数据非法,则输出“Wrong Format”;
(2)如果输入数据合法,但三条边不能构成三角形,则输出“Not a triangle”;
(3)如果输入数据合法且能够成等边三角形,则输出“Equilateral triangle”;
(3)如果输入数据合法且能够成等腰直角三角形,则输出“Isosceles right-angled triangle”;
(5)如果输入数据合法且能够成等腰三角形,则输出“Isosceles triangle”;
(6)如果输入数据合法且能够成直角三角形,则输出“Right-angled triangle”;
(7)如果输入数据合法且能够成一般三角形,则输出“General triangle”。
源码如下:
import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); double a,b,c; a=in.nextDouble(); b=in.nextDouble(); c=in.nextDouble(); float e,f,g; e=(float)(a*a); f=(float)(b*b); g=(float)(c*c); if(a<1||b<1||c<1||a>200||b>200||c>200){ System.out.println("Wrong Format"); } else{ if(a+b<=c||a+c<=b||b+c<=a){ System.out.println("Not a triangle"); } else { if(a==b&&a==c){ System.out.println("Equilateral triangle"); } else if(Math.abs(e-f-g)<1e-5||Math.abs(f-g-e)<1e-5||Math.abs(g-e-f)<1e-5){ if(a==b||b==c||a==c){ System.out.println("Isosceles right-angled triangle"); } else{ System.out.println("Right-angled triangle"); } } else if(a==b||b==c||a==c){ System.out.println("Isosceles triangle"); } else{ System.out.println("General triangle"); } } } } }
源码在source Mointor中分析可得其复杂度以及深度:

同时可以得到基维亚图和块直方图:

1.开始在判断不能构成三角形的情况错误将||编写为&&的情况,纯属是思路出现了致命错误;
2.本来开始认为只有依据三角形的各类型判断依据便可得出各种判断情况,但在我完成编写代码提交后在对直角三角形的判断中一直报错,在课堂上老师的提醒下1我才发现原来由于double与float的精度问题,当输入数的精度超过一定范围,不会存在准确的a*a+b*b=c*c这一类的情况,故我在了解到该情况后去改写了错误的代码,当误差在1e-5范围之内便可认定为相等;
else if(Math.abs(e-f-g)<1e-5||Math.abs(f-g-e)<1e-5||Math.abs(g-e-f)<1e-5){ if(a==b||b==c||a==c){ System.out.println("Isosceles right-angled triangle"); } else{ System.out.println("Right-angled triangle");
从此可以便可看出java编程中的严谨性,以后得多注意精度的问题;
5. 创建账户类Account(第三次题目集第二题)
源码如下:
import java.time.LocalDate; import java.util.Scanner; public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); int id=in.nextInt(); double balance=in.nextDouble(); double annuallnterestRate=in.nextDouble(); double withDraw=in.nextDouble(); double deposit=in.nextDouble(); Account account=new Account(); account.setter(id,balance,annuallnterestRate); account.withDraw(withDraw); account.deposit(deposit); System.out.printf("The Account'balance:%.2f\n",account.getbalance()); System.out.printf("The Monthly interest:%.2f\n",account.getMonthlyInterestRAte()); System.out.println("The Account'dateCreated:"+account.getDataCreated()); } } class Account{ private int id; private double balance; private double annuallnterestRate=0; private LocalDate dataCreated; public void setter(int id,double balance,double annuallnterestRate){ this.id=id; this.balance=balance; this.annuallnterestRate=annuallnterestRate; } public int getId(){ return id; } public double getbalance(){ return balance; } public double getann(){ return annuallnterestRate; } public LocalDate getDataCreated(){ this.dataCreated=LocalDate.of(2020,7,31); return this.dataCreated; } public void withDraw(double withDraw){ if(withDraw>balance||withDraw<0){ System.out.println("WithDraw Amount Wrong"); } else{ this.balance-=withDraw; } } public void deposit(double deposit){ if(deposit>20000||deposit<0){ System.out.println("Deposit Amount Wrong"); } else{ this.balance+=deposit; } } public double getMonthlyInterestRAte(){ return this.balance*(this.annuallnterestRate/1200); } }
开始在看到题目要求中:私有属性,LocalDate类型时有些懵,第一次见到,在查阅后发现使用该类型的得引入import java.util.LocalData去实现;
import java.time.LocalDate;
同时要细心去发现题目中存在的存、取款金额的限制问题,避免多余的麻烦;
三.踩坑心得
1.在第二次最后一道求下一天的提交中由于忘记对输入数据进行二月分天数限制的判断故存在答案错误,在加上判断后发现代码长度超过限度,主要原因是我在代码编程中没有做到求简的规则,一味地去实现一点一点的功能实现,忽略了对自身思路的精简提炼,如在月份与日期的定义上可以去以数组的方式去实现;
2.在第一次题目集中第七题的查找类题目,想到的是传统的for循环的方法,但代码的建立不是盲目去守旧去完成任务我们可以通过创新式的方法,如二分法,两头向中遍历法去减少代码的运行长度,达到提高效率的目的;
3.在第三次的第二题对未知类型数据的应用上,缺乏思考,一味地去认为可以返回三个数据而使用常规方法,再尝试多次后一直报错,然后才去查阅资料,浪费大量时间。因此在面对未知的知识区时不要一直死磕,及时制止去翻阅资料达到事半功倍的效果;
4.在第三次的第三、四题中,在对日期类的多个方法建立中,频繁出现错误,故在代码的设立中一定要去梳理好思路以及逻辑,盲目的去走一步看一步会让我们在完成代码上出现大量的混乱逻辑,例如在判断闰年的位置总是出现差错,在多次代码查询后才发现是位置的错误;
5.在对第一次的第五题的编码中,对数组中数据的遍历仍然以C语言的思维去思考,导致一直有逻辑错误,主要也是不了解Java中对数组的方法有哪些,在对java书的数组知识查阅后,发现可以通过s.indexOf(b)==s.lastIndexOf(b)的方式去判断数据在数组中的首次出现位置和最后一次出现位置,方便了解题;
四.改进建议
1.在第一次题目中的第七题,在较为复杂的数组中去查找是否存在某字符,在循环查找中可以运用二分法及两头法去减少对循环的次数,以达到更精简的处理方式;
2.在对第二次最后一个求下一天类题目的编程中我们可以通过对月日放在同一数组中去进行相应运行以减少代码量,而不是一味地分开定义而使得每次月份以及年份改变都要去进行一次判定日期的方式去使得代码变得意义少且杂乱;
3.在对数据的输出中要求输出几位小数,我们可以通过String .format( "%.4f" ,u)或者直接printf("",);的方式去实现;
4.在第一次7-8题目中在对一个从字符串中提取部分字符的要求,我们可以通过建立一个新的空字符串的方式,以append()的方式存入字符,以达到简便明了的实现功能;
5.在第一次的最后一题中有递归的方法运用,我们可以通过设立函数(方法)的方式去更快达到目的,而不是借助while()的方式;
五.总结
这三次题目集的练习让我对Java编程的严谨以及逻辑有了更加深刻的认识,在面对java这样一门知识量大的新语言上应该抱有敬畏的态度,要调整自己对问题的思考方式,不断的去创新和思考,改变自己的代码编写习惯,同时也要参考阿里代码准则去规范自己;这几次练习也让我对java类的应用和私有属性有了更加深刻的认识,在数组的各类调用方法和循环结构,数据的精度以及对java方法的建立有了一定的经验;在这几次的Java练习中我也发现自身在对多项类的运用以及对私有属性的运用上有不熟练的问题,在往后的学习里我会更加注重这方面练习并加深理解,同时在对面向对象中各种普及的方法去深入学习;在对老师教学的提议上,希望老师可以在课堂上对pta每一次的较难点以及错误较多的点去进行一个细微的讲解,让我们在自己编写代码过后发现自己的不足,并及时去改正。

浙公网安备 33010602011771号