第四至六次作业总结
一、作业总结
第4次作业主要是类的设计,包括类的聚合,继承等。根据所给的类图设计即可难度适中,难点主要在于合法性检验,包括正则的设计等。
第5次作业继续设立类的聚合,对日期操作进一步整合。统计JAVA关键词则继续强化正则的使用,并且使用了map进行映射,难度适中。
第6次作业,前4题均为正则表达式的使用,难度简单,稍微掌握正则的基本语法即可,第5题为图形的基础和多态,涉及类的继承和多态,第6题为接口的实现,难度适中,按类图设计即可
二、设计与分析
日期聚合设计
在第4次作业7-2中,日期类设计要求设计如下几个类:DateUtil、Year、Month、Day,其中年、月、日的取值范围依然为:year∈[1900,2050] ,month∈[1,12] ,day∈[1,31] , 设计类图如下:

应用程序共测试三个功能:
-
求下n天
-
求前n天
-
求两个日期相差的天数
可以看到DateUtil要获取年月日的值都要一层一层的通过get方法,根据次设计出的源码如下
import java.util.*;
class Day {
private int value;
private Month month=new Month();
public int[] mon_maxnum= {31,28,31,30,31,30,31,31,30,31,30,31};
Day()
{
}
Day(int yearValue,int monthValue,int dayValue)
{
this.value=dayValue;
this.month.setValue(monthValue);
this.month.getYear().setValue(yearValue);
}
/**
* @return value
*/
public int getValue() {
return value;
}
/**
* @param value 要设置的 value
*/
public void setValue(int value) {
this.value = value;
}
/**
* @return month
*/
public Month getMonth() {
return month;
}
/**
* @param month 要设置的 month
*/
public void setMonth(Month month) {
this.month = month;
}
void resetMin()
{
this.value=1;
}
void resetMax()
{
if(this.month.getValue()==2&&this.month.getYear().isLeapYear())
{
this.value=29;
}
else
this.value=mon_maxnum[this.month.getValue()-1];
}
boolean validate()
{
if(this.month.getYear().isLeapYear())
mon_maxnum[1]=29;
else
mon_maxnum[1]=28;
if(this.month.validate()&&this.value>=1&&this.value<=mon_maxnum[this.month.getValue()-1])
return true;
return false;
}
void dayIncrement()
{
this.value+=1;
}
void daytRedution()
{
this.value-=1;
}
}
class Month {
private int value;
private Year year=new Year();
Month()
{
}
Month(int yearValue, int monthValue)
{
this.value=monthValue;
this.year.setValue(yearValue);
}
/**
* @return value
*/
public int getValue() {
return value;
}
/**
* @param value 要设置的 value
*/
public void setValue(int value) {
this.value = value;
}
/**
* @return year
*/
public Year getYear() {
return year;
}
/**
* @param year 要设置的 year
*/
public void setYear(Year year) {
this.year = year;
}
void resetMin()
{
this.value=1;
}
void resetMax()
{
this.value=12;
}
boolean validate()
{
if(this.value>=1&&this.value<=12)
return true;
return false;
}
void monthIncrement()
{
this.value+=1;
}
void monthReduction()
{
this.value-=1;
}
}
class Year {
private int value;
Year()
{
}
Year(int value)
{
this.value=value;
}
/**
* @return value
*/
public int getValue() {
return value;
}
/**
* @param value 要设置的 value
*/
public void setValue(int value) {
this.value = value;
}
boolean isLeapYear()
{
if((this.value%4==0&&this.value%100!=0)||this.value%400==0)
return true;
return false;
}
boolean validate()
{
if(this.value>=1900&&this.value<=2050)
return true;
return false;
}
void yearIncrement()
{
this.value+=1;
}
void yearReduction()
{
this.value-=1;
}
}
class DateUtil {
Day day=new Day();
DateUtil()
{
}
DateUtil(int d,int m,int y)
{
this.day.setValue(d);
this.day.getMonth().setValue(m);
this.day.getMonth().getYear().setValue(y);
}
/**
* @return day
*/
public Day getDay() {
return day;
}
/**
* @param day 要设置的 day
*/
public void setDay(Day day) {
this.day = day;
}
boolean checkInputValidity()
{
if(this.day.validate()&&this.day.getMonth().getYear().validate())
return true;
return false;
}
boolean compareDates(DateUtil date)
{
if(this.day.getMonth().getYear().getValue()>date.day.getMonth().getYear().getValue())
return true;
else if(this.day.getMonth().getYear().getValue()<date.day.getMonth().getYear().getValue())
return false;
else
{
if(this.day.getMonth().getValue()>date.day.getMonth().getValue())
return true;
else if(this.day.getMonth().getValue()<date.day.getMonth().getValue())
return false;
else
{
if(this.day.getValue()>date.day.getValue())
return true;
else
return false;
}
}
}
boolean equalTwoDates(DateUtil date)
{
if(this.day.getMonth().getYear().getValue()==date.day.getMonth().getYear().getValue()
&&this.day.getMonth().getValue()==date.day.getMonth().getValue()
&&this.day.getValue()==date.day.getValue())
return true;
return false;
}
String showDate()
{
return this.day.getMonth().getYear().getValue()+"-"+this.day.getMonth().getValue()+"-"+this.day.getValue();
}
DateUtil getNextNDays(int n)
{
if(n>0)
{
while(n-->0)
{
this.day.dayIncrement();
if(!this.day.validate())
{
this.day.getMonth().monthIncrement();
if(this.day.getMonth().getValue()==13)
{
this.day.getMonth().resetMin();
this.day.getMonth().getYear().yearIncrement();
}
this.day.resetMin();
}
}
}
else if(n<0)
getPreviousNDays(-n);
return this;
}
DateUtil getPreviousNDays(int n)
{
if(n>0)
{
while(n-->0)
{
this.day.daytRedution();
if(!this.day.validate())
{
this.day.getMonth().monthReduction();
if(this.day.getMonth().getValue()==0)
{
this.day.getMonth().resetMax();
this.day.getMonth().getYear().yearReduction();
}
this.day.resetMax();
}
}
}
else if(n<0)
getNextNDays(-n);
return this;
}
int getDaysofDates(DateUtil date)
{
int count1=0,count2=0;
int sum1=0,sum2=0;
int count=0;
if(this.equals(date))
return 0;
else
{
if(this.day.getMonth().getYear().isLeapYear())
this.day.mon_maxnum[1]=29;
else
this.day.mon_maxnum[1]=28;
for(int i=0;i<this.day.getMonth().getValue()-1;i++)
{
count1+=this.day.mon_maxnum[i];
}
count1+=this.day.getValue();
sum1=(this.day.getMonth().getYear().getValue()-1)*365+(this.day.getMonth().getYear().getValue()-1)/4-(this.day.getMonth().getYear().getValue()-1)/100+(this.day.getMonth().getYear().getValue()-1)/400;
count1+=sum1;
if(date.day.getMonth().getYear().isLeapYear())
date.day.mon_maxnum[1]=29;
else
date.day.mon_maxnum[1]=28;
for(int i=0;i<date.day.getMonth().getValue()-1;i++)
{
count2+=date.day.mon_maxnum[i];
}
count2+=date.day.getValue();
sum2=(date.day.getMonth().getYear().getValue()-1)*365+(date.day.getMonth().getYear().getValue()-1)/4-(date.day.getMonth().getYear().getValue()-1)/100+(date.day.getMonth().getYear().getValue()-1)/400;
count2+=sum2;
count=Math.abs(count1-count2);
return count;
}
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
int oper=0;
int y1=0,m1=0,d1=0,count=0,y2=0,m2=0,d2=0;
oper=input.nextInt();
switch(oper)
{
case 1: y1=input.nextInt();m1=input.nextInt();d1=input.nextInt();count=input.nextInt();
DateUtil date1=new DateUtil(d1,m1,y1);
if(date1.checkInputValidity())
{
date1.getNextNDays(count);
System.out.println(date1.showDate());
}
else
System.out.println("Wrong Format");
break;
case 2: y1=input.nextInt();m1=input.nextInt();d1=input.nextInt();count=input.nextInt();
DateUtil date2=new DateUtil(d1,m1,y1);
if(date2.checkInputValidity())
{
date2.getPreviousNDays(count);
System.out.println(date2.showDate());
}
else
System.out.println("Wrong Format");
break;
case 3: y1=input.nextInt();m1=input.nextInt();d1=input.nextInt();
y2=input.nextInt();m2=input.nextInt();d2=input.nextInt();
DateUtil date3=new DateUtil(d1,m1,y1);
DateUtil date4=new DateUtil(d2,m2,y2);
if(date3.checkInputValidity()&&date4.checkInputValidity())
{
int sum=date3.getDaysofDates(date4);
System.out.println(sum);
}
else
System.out.println("Wrong Format");
break;
default:System.out.println("Wrong Format");
}
input.close();
}
}
第5次中日期类之间的关系有所变化,具体类图如下

可以看到在这种设计下,从DateUtil类即可一次通过get方法获取到年月日的值,方便处理
图形继承设计
第4次作业7-3图形继承
编写程序,实现图形类的继承,并定义相应类对象并进行测试。
- 类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
次题仅涉及类的继承,所有图形都继承Shape类,具体类图如下

源码如下
import java.util.*;
class Shape {
public double getArea()//求图形面积
{
return 0;
}
Shape()
{
System.out.println("Constructing Shape");
}
}
class Circle extends Shape {
private double radius=0;
public double getArea()
{
return Math.PI*this.radius*this.radius;
}
Circle(double radius)
{
super();
System.out.println("Constructing Circle");
this.radius=radius;
}
/**
* @return radius
*/
public double getRadius() {
return radius;
}
/**
* @param radius 要设置的 radius
*/
public void setRadius(double radius) {
this.radius = radius;
}
}
class Rectangle extends Shape {
private double width;
private double length;
public Rectangle(double width, double length) {
super();
System.out.println("Constructing Rectangle");
this.width = width;
this.length = length;
}
/**
* @return width
*/
public double getWidth() {
return width;
}
/**
* @param width 要设置的 width
*/
public void setWidth(double width) {
this.width = width;
}
/**
* @return length
*/
public double getLength() {
return length;
}
/**
* @param length 要设置的 length
*/
public void setLength(double length) {
this.length = length;
}
public double getArea()
{
return this.length*this.width;
}
}
class Box extends Rectangle {
private double height;
public Box(double width, double length,double height) {
super(width, length);
// TODO 自动生成的构造函数存根
this.height=height;
System.out.println("Constructing Box");
}
public double getArea()
{
return 2*(this.getLength()*this.getWidth()+this.height*this.getLength()+this.height*this.getWidth());
}
public double getVolume()//求立方体体积
{
return this.height*this.getLength()*this.getWidth();
}
}
class Ball extends Circle {
public Ball(double radius) {
super(radius);
// TODO 自动生成的构造函数存根
System.out.println("Constructing Ball");
}
public double getArea()
{
return 4*Math.PI*this.getRadius()*this.getRadius();
}
public double getVolume()//求球体积
{
return 4.0/3*Math.PI*Math.pow(getRadius(), 3);
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input=new Scanner(System.in);
int oper=0;
double radius=0,width=0,length=0,height=0;
double area=0,volu=0;
oper=input.nextInt();
switch(oper)
{
case 1:radius=input.nextDouble();
if(radius<0)
{
System.out.println("Wrong Format");
}
else
{
Circle c=new Circle(radius);
area=c.getArea();
System.out.println("Circle's area:"+String.format("%.2f", area));
}break;
case 2:width=input.nextDouble(); length=input.nextDouble();
if(width<0||length<0)
{
System.out.println("Wrong Format");
}
else
{
Rectangle r=new Rectangle(width,length);
area=r.getArea();
System.out.println("Rectangle's area:"+String.format("%.2f", area));
}break;
case 3:
radius=input.nextDouble();
if(radius<0)
{
System.out.println("Wrong Format");
}
else
{
Ball b=new Ball(radius);
area=b.getArea();
volu=b.getVolume();
System.out.println(String.format("Ball's surface area:"+"%.2f", area));
System.out.println(String.format("Ball's volume:"+"%.2f", volu));
}break;
case 4:width=input.nextDouble(); length=input.nextDouble();
height=input.nextDouble();
if(width<0||length<0||height<0)
{
System.out.println("Wrong Format");
}
else
{
Box b=new Box(width,length,height);
area=b.getArea();
volu=b.getVolume();
System.out.println(String.format("Box's surface area:"+"%.2f", area));
System.out.println(String.format("Box's volume:"+"%.2f", volu));
}break;
default:System.out.println("Wrong Format");
}
input.close();
}
}
第6次作业7-5
从键盘首先输入三个整型值(例如a b c),分别代表想要创建的Circle、Rectangle及Triangle对象的数量,然后根据图形数量继续输入各对象的属性值(均为实型数),数与数之间可以用一个或多个空格或回车分隔。
输出格式:
- 如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边关系),则输出
Wrong Format。 - 如果输入合法,则正常输出,输出内容如下(输出格式见输入输出示例):
- 各个图形的面积;
- 所有图形的面积总和;
- 排序后的各个图形面积;
- 再次所有图形的面积总和。
类图简略设计如下

getArea()方法为抽象方法,功能为求得图形的面积;validate()方法也为抽象方法,对图形的属 性进行合法性校验;toString()继承自 Object,功能为输出图形的面积信息
此题涉及到了类的继承及多态
源码如下
import java.util.ArrayList;
import java.util.Collections;
import java.util.Scanner;
import java.util.Comparator;
abstract class Shape {
abstract double getArea();
abstract boolean validate();
public String toString()
{
return "Wrong Format";
}
}
class Circle extends Shape {
public Circle()
{
}
public Circle(double radius) {
super();
this.radius = radius;
}
private double radius;
/**
* @return radius
*/
public double getRadius() {
return radius;
}
/**
* @param radius 要设置的 radius
*/
public void setRadius(double radius) {
this.radius = radius;
}
public double getArea()
{
return Math.PI*this.radius*this.radius;
}
@Override
boolean validate() {
// TODO 自动生成的方法存根
if(this.radius<=0)
return false;
return true;
}
}
class Rectangle extends Shape{
public Rectangle()
{
}
public Rectangle(double weight, double length) {
super();
this.weight = weight;
this.length = length;
}
private double weight;
private double length;
/**
* @return weight
*/
public double getWeight() {
return weight;
}
/**
* @param weight 要设置的 weight
*/
public void setWeight(double weight) {
this.weight = weight;
}
/**
* @return length
*/
public double getLength() {
return length;
}
/**
* @param length 要设置的 length
*/
public void setLength(double length) {
this.length = length;
}
public double getArea()
{
return this.length*this.weight;
}
@Override
boolean validate() {
// TODO 自动生成的方法存根
if(this.length<=0||this.weight<=0)
return false;
return true;
}
}
class Triangle extends Shape{
public Triangle()
{
}
public Triangle(double side1, double side2, double side3) {
super();
this.side1 = side1;
this.side2 = side2;
this.side3 = side3;
}
private double side1;
private double side2;
private double side3;
/**
* @return side1
*/
public double getSide1() {
return side1;
}
/**
* @param side1 要设置的 side1
*/
public void setSide1(double side1) {
this.side1 = side1;
}
/**
* @return side2
*/
public double getSide2() {
return side2;
}
/**
* @param side2 要设置的 side2
*/
public void setSide2(double side2) {
this.side2 = side2;
}
/**
* @return side3
*/
public double getSide3() {
return side3;
}
/**
* @param side3 要设置的 side3
*/
public void setSide3(double side3) {
this.side3 = side3;
}
@Override
double getArea() {
// TODO 自动生成的方法存根
double p=0.5*(side1+side2+side3);
return Math.sqrt((p*(p-side1)*(p-side2)*(p-side3)));
}
@Override
boolean validate() {
// TODO 自动生成的方法存根
if(side1<=0||side2<=0||side3<=0||side1+side2<=side3||side1+side3<=side2||side2+side3<=side1)
return false;
return true;
}
}
class SortArea implements Comparator<Shape>{
@Override
public int compare(Shape o1, Shape o2) {
// TODO 自动生成的方法存根
if(o1.getArea()-o2.getArea()>0)
return 1;
else if(o1.getArea()-o2.getArea()<0)
return -1;
else
return 0;
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
/*
Scanner input= new Scanner(System.in);
double r,w,l;
r=input.nextDouble();
w=input.nextDouble();
l=input.nextDouble();
input.close();
if(r>0&&w>0&&l>0)
{
Circle circle=new Circle(r);
Rectangle rec=new Rectangle(w,l);
System.out.println(String.format("%.2f",circle.getArea()));
System.out.println(String.format("%.2f",rec.getArea()));
}
else
{
System.out.println("Wrong Format");
return ;
}
*/
Scanner input= new Scanner(System.in);
int countCircle,countRectangle,countTriangle;
double r,w,l,s1,s2,s3;
countCircle=input.nextInt();
countRectangle=input.nextInt();
countTriangle=input.nextInt();
if(countCircle<0||countRectangle<0||countTriangle<0)
{
System.out.println("Wrong Format");
return ;
}
Circle circle=new Circle();
Rectangle rect=new Rectangle();
Triangle tri=new Triangle();
ArrayList<Shape> shape=new ArrayList<Shape>();
for(int i=0;i<countCircle;i++)
{
r=input.nextDouble();
circle.setRadius(r);
if(!circle.validate())
{
System.out.println("Wrong Format");
return ;
}
shape.add(new Circle(r));
}
for(int i=0;i<countRectangle;i++)
{
w=input.nextDouble();
l=input.nextDouble();
rect.setLength(l);
rect.setWeight(w);
if(!rect.validate())
{
System.out.println("Wrong Format");
return ;
}
shape.add(new Rectangle(w,l));
}
for(int i=0;i<countTriangle;i++)
{
s1=input.nextDouble();
s2=input.nextDouble();
s3=input.nextDouble();
tri.setSide1(s1);
tri.setSide2(s2);
tri.setSide3(s3);
if(!tri.validate())
{
System.out.println("Wrong Format");
return ;
}
shape.add(new Triangle(s1,s2,s3));
}
double sumArea=0;
System.out.println("Original area:");
for(Shape sh:shape)
{
System.out.print(String.format("%.2f", sh.getArea())+" ");
sumArea+=sh.getArea();
}
System.out.println();
System.out.println("Sum of area:"+String.format("%.2f", sumArea));
System.out.println("Sorted area:");
Collections.sort(shape,new SortArea());
sumArea=0;
for(Shape sh:shape)
{
System.out.print(String.format("%.2f", sh.getArea())+" ");
sumArea+=sh.getArea();
}
System.out.println();
System.out.println("Sum of area:"+String.format("%.2f", sumArea));
}
}
7-6编写程序,使用接口及类实现多态性,类图结构如下所示:

其中:
- GetArea为一个接口,无属性,只有一个GetArea(求面积)的抽象方法;
- Circle及Rectangle分别为圆类及矩形类,分别实现GetArea接口
- 要求:在Main类的主方法中分别定义一个圆类对象及矩形类对象(其属性值由键盘输入),使用接口的引用分别调用圆类对象及矩形类对象的求面积的方法,直接输出两个图形的面积值。(要求只保留两位小数)
输入格式:
从键盘分别输入圆的半径值及矩形的宽、长的值,用空格分开。
输出格式:
-
如果输入的圆的半径值及矩形的宽、长的值非法(≤0),则输出
Wrong Format -
如果输入合法,则分别输出圆的面积和矩形的面积值(各占一行),保留两位小数。
此题出现了接口的使用,将各图形的getArea()方法定义为一个接口,由各图形类实现该方法
源码如下
import java.util.Scanner;
interface GetArea {
public double getArea();
}
class Circle implements GetArea {
public Circle()
{
}
public Circle(double radius) {
super();
this.radius = radius;
}
private double radius;
/**
* @return radius
*/
public double getRadius() {
return radius;
}
/**
* @param radius 要设置的 radius
*/
public void setRadius(double radius) {
this.radius = radius;
}
public double getArea()
{
return Math.PI*this.radius*this.radius;
}
}
class Rectangle implements GetArea{
public Rectangle()
{
}
public Rectangle(double weight, double length) {
super();
this.weight = weight;
this.length = length;
}
private double weight;
private double length;
/**
* @return weight
*/
public double getWeight() {
return weight;
}
/**
* @param weight 要设置的 weight
*/
public void setWeight(double weight) {
this.weight = weight;
}
/**
* @return length
*/
public double getLength() {
return length;
}
/**
* @param length 要设置的 length
*/
public void setLength(double length) {
this.length = length;
}
public double getArea()
{
return this.length*this.weight;
}
}
public class Main {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner input= new Scanner(System.in);
double r,w,l;
r=input.nextDouble();
w=input.nextDouble();
l=input.nextDouble();
input.close();
if(r>0&&w>0&&l>0)
{
Circle circle=new Circle(r);
Rectangle rec=new Rectangle(w,l);
System.out.println(String.format("%.2f",circle.getArea()));
System.out.println(String.format("%.2f",rec.getArea()));
}
else
{
System.out.println("Wrong Format");
return ;
}
}
}
java 封装 继承 多态的总结
封装:
1.定义:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别。
2.封装的目的是:增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,一特定的访问权限来使用类的成员。
3.封装的基本要求是:把所有的属性私有化,对每个属性提供getter和setter方法,如果有一个带参的构造函数的话,那一定要写一个不带参的构造函数。在开发的时候经常要对已经编写的类进行测试,所以在有的时候还有重写toString方法,但这不是必须的。
继承:
1.目的:
实现代码的复用。
2.介绍:
当两个类具有相同的特征(属性)和行为(方法)时,可以将相同的部分抽取出来放到一个类中作为父类,其它两个类继承这个父类。继承后子类自动拥有了父类的属性和方法,但特别注意的是,父类的私有属性和构造方法并不能被继承。另外子类可以写自己特有的属性和方法,目的是实现功能的扩展,子类也可以复写父类的方法即方法的重写。子类不能继承父类中访问权限为private的成员变量和方法。子类可以重写父类的方法,及命名与父类同名的成员变量。有时候我们需要这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到protected。
多态:
1.概念:
相同的事物,调用其相同的方法,参数也相同时,但表现的行为却不同。
2.Java实现多态有三个必要条件:
继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
3.多态的实现方式:
(1)基于继承实现的多态
基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。
(2)基于接口实现的多态
继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。
在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
4.多态性主要表现在如下两个方面:
(1)方法重载.通常指在同一个类中,相同的方法名对应着不同的方法实现,但是方法的参数不同.
(2)成员覆盖.通常指在不同类(父类和子类)中,允许有相同的变量名,但是数据类型不同;也允许有相同的方法名,但是对应的方法实现不同.
5.多态的好处:
程序的可扩展性及可维护性增强。
正则表达式总结
在这三次作业中,大量使用了正则表达式来检验合法性,如日期的合法性等
正则表达式语法
在其他语言中,\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义。
在 Java 中,\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
所以,在其他的语言中(如 Perl),一个反斜杠 ** 就足以具有转义的作用,而在 Java 中正则表达式中则需要有两个反斜杠才能被解析为其他语言中的转义作用。也可以简单的理解在 Java 的正则表达式中,两个 \ 代表其他语言中的一个 ****,这也就是为什么表示一位数字的正则表达式是 \d,而表示一个普通的反斜杠是 \。
| 字符 | 说明 |
|---|---|
| \ | 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如, n匹配字符 n。\n 匹配换行符。序列 \\ 匹配 \ ,\( 匹配 (。 |
| ^ | 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"\n"或"\r"之后的位置匹配。 |
| $ | 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。 |
| * | 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。 |
| + | 一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。 |
| ? | 零次或一次匹配前面的字符或子表达式。例如,"do(es)?"匹配"do"或"does"中的"do"。? 等效于 {0,1}。 |
| {n} | n 是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配。 |
| {n,} | n 是非负整数。至少匹配 n 次。例如,"o{2,}"不匹配"Bob"中的"o",而匹配"foooood"中的所有 o。"o{1,}"等效于"o+"。"o{0,}"等效于"o*"。 |
| {n,m} | m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。'o{0,1}' 等效于 'o?'。注意:您不能将空格插入逗号和数字之间。 |
| ? | 当此字符紧随任何其他限定符(、+、?、{n}、{n,}、{n,m*})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?"只匹配单个"o",而"o+"匹配所有"o"。 |
| . | 匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式。 |
| (pattern) | 匹配 pattern 并捕获该匹配的子表达式。可以使用 $0…$9 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用"("或者")"。 |
| (?:pattern) | 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 (|) 组合模式部件的情况很有用。例如,'industr(?:y|ies) 是比 'industry|industries' 更经济的表达式。 |
| (?=pattern) | 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?=95|98|NT|2000)' 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 |
| (?!pattern) | 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?!95|98|NT|2000)' 匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 |
| x|y | 匹配 x 或 y。例如,'z|food' 匹配"z"或"food"。'(z|f)ood' 匹配"zood"或"food"。 |
| [xyz] | 字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。 |
| [^xyz] | 反向字符集。匹配未包含的任何字符。例如,"[^abc]"匹配"plain"中"p","l","i","n"。 |
| [a-z] | 字符范围。匹配指定范围内的任何字符。例如,"[a-z]"匹配"a"到"z"范围内的任何小写字母。 |
| [^a-z] | 反向范围字符。匹配不在指定的范围内的任何字符。例如,"[^a-z]"匹配任何不在"a"到"z"范围内的任何字符。 |
| \b | 匹配一个字边界,即字与空格间的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。 |
| \B | 非字边界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。 |
| \cx | 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身。 |
| \d | 数字字符匹配。等效于 [0-9]。 |
| \D | 非数字字符匹配。等效于 [^0-9]。 |
| \f | 换页符匹配。等效于 \x0c 和 \cL。 |
| \n | 换行符匹配。等效于 \x0a 和 \cJ。 |
| \r | 匹配一个回车符。等效于 \x0d 和 \cM。 |
| \s | 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。 |
| \S | 匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。 |
| \t | 制表符匹配。与 \x09 和 \cI 等效。 |
| \v | 垂直制表符匹配。与 \x0b 和 \cK 等效。 |
| \w | 匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]"等效。 |
| \W | 与任何非单词字符匹配。与"[^A-Za-z0-9_]"等效。 |
| \xn | 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,"\x41"匹配"A"。"\x041"与"\x04"&"1"等效。允许在正则表达式中使用 ASCII 代码。 |
| *num* | 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)\1"匹配两个连续的相同字符。 |
| *n* | 标识一个八进制转义码或反向引用。如果 *n* 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。 |
| *nm* | 标识一个八进制转义码或反向引用。如果 *nm* 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 *nm* 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 *nm* 匹配八进制值 nm,其中 n 和 m 是八进制数字 (0-7)。 |
| \nml | 当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。 |
| \un | 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。 |
Matcher 类的方法
索引方法
索引方法提供了有用的索引值,精确表明输入字符串中在哪能找到匹配:
| 序号 | 方法及说明 |
|---|---|
| 1 | public int start() 返回以前匹配的初始索引。 |
| 2 | public int start(int group) 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引 |
| 3 | public int end() 返回最后匹配字符之后的偏移量。 |
| 4 | public int end(int group) 返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。 |
查找方法
查找方法用来检查输入字符串并返回一个布尔值,表示是否找到该模式:
| 序号 | 方法及说明 |
|---|---|
| 1 | public boolean lookingAt() 尝试将从区域开头开始的输入序列与该模式匹配。 |
| 2 | public boolean find() 尝试查找与该模式匹配的输入序列的下一个子序列。 |
| 3 | public boolean find(int start****) 重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。 |
| 4 | public boolean matches() 尝试将整个区域与模式匹配。 |
替换方法
替换方法是替换输入字符串里文本的方法:
| 序号 | 方法及说明 |
|---|---|
| 1 | public Matcher appendReplacement(StringBuffer sb, String replacement) 实现非终端添加和替换步骤。 |
| 2 | public StringBuffer appendTail(StringBuffer sb) 实现终端添加和替换步骤。 |
| 3 | public String replaceAll(String replacement) 替换模式与给定替换字符串相匹配的输入序列的每个子序列。 |
| 4 | public String replaceFirst(String replacement) 替换模式与给定替换字符串匹配的输入序列的第一个子序列。 |
| 5 | public static String quoteReplacement(String s) 返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。 |
三、踩坑心得
第4次作业水文数据校验及处理中,没注意一行数据不是合法的’|‘分隔的五个部分应该输出Wrong Format Data:输入的数据,而不是输出每个列都错误。日期设计中,常常出现数组越界的问题,没考虑清楚逻辑。
第5次作业中,统计关键词数量题目测试点出错,一个null没有计入导致测试点一直过不去,最终采用对特殊点的特殊处理通过了,部分代码如下
for(int i=0;i<key.length;i++)
{
c=map.get(key[i]);
if(count!=53&&word.length<800&&i==32)
c=0;
if(c!=0)
{
System.out.printf("%d\t",c);
System.out.println(key[i]);
}
}
四、改进建议
第四次作业7-1水文数据校验及处理的设计过于繁琐,复用性不高
五、总结
通过这几次的作业,我对于java的封装继承和多态有了更深的理解,其次对正则的使用也更加的熟练了并再次感受到了正则的强大与方便之处。

浙公网安备 33010602011771号