一、实验目的
通过编程和上机实验,掌握类和构造方法的定义及创建对象的方法,掌握类的封装及继承原则,正确使用重载和覆盖等多态概念设计可复用方法,熟悉包、接口的使用方法,掌握面向对象的程序设计方法。
二、实验内容
1、编写 MyDate 类,完善上次实验中的人员信息录入,实现日期合法性判 断,包括大小月和闰年。
*2、声明一个 Person 类和派生类 Student,成员变量包括学号、姓名、入学时间、身份证号、学分绩点等信息,成员方法包括开户、存款、取款、查询(余 额、明细)、销户等操作。
*3、设计一个汽车类Vehicle,包含的属性有车轮个数(wheels)和车重(weight)。小车类 Car 是 Vehicle 类的子类,其中包含的属性有载人数(loader)。卡车类(Truck类)是 Car 类的子类,其中包含的属性有载重量(payload)。每一个类都有相关数据的输出。
实验要求:(1)汽车类 Vehicle 的构造方法带有 2 个参数,分别是 wheels 和weight。Car 类的构造方法带有 3 个参数,分别为 wheels、weight 和 loader。Truck的构造方法带有 4 个参数,分别为 wheels、weight、loader 和 payload。
4、定义接口 Shape 及其抽象方法 getArea()和 getPerimeter()用于计算图形和面积和周长。定义类 Rectangle(矩形)、类 Circle(圆形)、类 Triangle(三角形),要求这些类继承点类 Coordinates()并实现接口的抽象方法。
提示:
class Coordinates
{
long x;
long y;
Coordinate(long x, long y)
{
this.x=x;
this.y=y;
}
}
5、包的定义和使用
(1)创建自定义包 Mypackage
在存放源程序的文件夹中建立一个子文件夹 Mypackage。例如,在“E:\java\ 程序”文件夹之中创建一个与包同名的子文件夹 Mypackage(E:\java\程序\Mypackage),并将编译过的 class 文件放入该文件夹中。注意:包名与文件夹名大小写要一致。再添加环境变量 classpath 的路径,例如:E:\j2sdk1.4.2_01\lib;E:\java\程序
(2)在包中创建类
YMD.java 程序功能:在源程序中,首先声明使用的包名 Mypackage,然后
创建 YMD 类,该类具有计算今年的年份并输出一个带有年月日的字符串的功 能。源代码如下:
编译 Test_YMD.java 文件,然后将 Test_YMD.class 文件存放到 Mypackage文件夹中。
(3)编写使用包 Mypackage 中 Test_YMD 类的程序
YMD_2.java 程序功能:给定某人姓名与出生日期,计算该人年龄,并输出该人姓名,年龄,出生日期。程序使用了 Test_YMD 的方法来计算年龄。源代码如下:
编译并运行程序。
三、实验程序源代码
1、
import java.util.Scanner;
import java.util.ArrayList;
class MyDate{
public int year;
public int month;
public int day;
public MyDate(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
public static boolean isLeapyear(int year){
return (year%400==0)||(year%100!=0&&year%4==0);
}
public static int Dayofmonth(int year,int month){
switch(month){
case 1:case 3:case 5:case 7:case 8:case 10:case 12: return 31;
case 2: return MyDate.isLeapyear(year)?29:28;
case 4:case 6:case 9:case 11: return 30;
default: return 0;
}
}
public static boolean isValidDate(int year,int month,int day){
return (year>0&&year<=2022)&&(month>0&&month<=12)&&(day>0&&day<=Dayofmonth(year,month));
}
}
class Student extends MyDate{
String name;
int age;
double score;
public Student(String name,int age,double score,int year,int month,int day){
super(year,month,day);
this.name=name;
this.age=2022-year;
this.score=score;
}
public static void main(String args[])
{
int n=10;
String name;
int age;
double score;
int year;
int month;
int day;
Scanner stu=new Scanner(System.in);
System.out.println("请按顺序输入学生信息:姓名 年龄 Java实验成绩 出生日期");
ArrayList<Student> s=new ArrayList<>();
for(int i=0;i<n;i++){
name=stu.next();
age=stu.nextInt();
score=stu.nextDouble();
year=stu.nextInt();
month=stu.nextInt();
day=stu.nextInt();
s.add(new Student(name,age,score,year,month,day));
if(!s.get(i).isValidDate(year,month,day)){
System.out.println("生日日期无效");
}
else{
System.out.println("生日是闰年吗?"+s.get(i).isLeapyear(year));
if(s.get(i).Dayofmonth(year,month)==31){
System.out.println("生日月份是大月");
}
else if(s.get(i).Dayofmonth(year,month)==30){
System.out.println("生日月份是小月");
}
else if(s.get(i).Dayofmonth(year,month)==29||s.get(i).Dayofmonth(year,month)==28){
System.out.println("生日月份既不是大月也不是小月,是二月");
}
}
}
stu.close();
}
}
2、
import java.util.*;
import java.text.SimpleDateFormat;
class MyDate{
public int year;
public int month;
public int day;
public MyDate(int year,int month,int day){
this.year=year;
this.month=month;
this.day=day;
}
}
class Person{
public String name;//姓名
public String ID;//身份证号
public String password;//密码
public int age;//年龄
MyDate birth;
Person(String name,String ID,String password,int age,int year,int month,int day){
this.name=name;
this.ID=ID;
this.password=password;
this.age=age;
birth=new MyDate(year,month,day);
}
}
class Student extends Person {
public String Sno;//学号
public double GPA;//学分绩点
Student(String name,String ID,String password,int age,int year,int month,int day,String sno,double gpa){
super(name,ID,password,age,year,month,day);
Sno=sno;
GPA=gpa;
}
public double balance=0;//余额
StringBuffer a=new StringBuffer();
public StringBuffer geta(){
return a;
}
SimpleDateFormat t=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//时间格式设置
public void Deposit(int n){
balance+=n;
a.append(t.format(new Date())).append("\n").append("存款:").append(n).append("元,余额:").append(balance).append("元\n");
System.out.println("存款成功!");
}
public void Withdraw(int n){
if(balance>=n){
balance-=n;
a.append(t.format(new Date())).append("\n").append("取款:").append(n).append("元,余额:").append(balance).append("元\n");
System.out.println("取款成功!");
}
else{
System.out.println("余额不足,请重新输入取款金额");
}
}
@Override
public boolean equals(Object o){
if(this==o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Sno.equals(student.Sno);
}
}
class A{
ArrayList<Student> arr=new ArrayList<>();
public Student getItem(int index){
if(index<arr.size())
return arr.get(index);
else return null;
}
public int search(String password){
for(int index=0;index<arr.size();index++){
if (Objects.equals(arr.get(index).password, password))
return index;
}
return -1;
}
public void Open(Student s){
arr.add(s);
}
public void Close(Student s){
arr.remove(s);
}
public static void main(String args[]){
String name;
String ID;
String password;
int age;
String Sno;//学号
double GPA;//学分绩点
int year;
int month;
int day;
A m=new A();
while(true){
Scanner scan=new Scanner(System.in);
System.out.println("\n请输入数字:");
System.out.println("输入1:开户\n 输入2:销户\n 输入3:查询\n 输入4:存款\n 输入5:取款\n 输入其他数字:退出\n");
int n=scan.nextInt();
switch(n){
case 1:{
System.out.println("输入学生人数:");
int num=scan.nextInt();
System.out.println("请输入学生信息: 姓名 身份证号 密码 年龄 生日日期 学号 学分绩点");
for(int i=0;i<num;i++){
name=scan.next();
ID=scan.next();
password=scan.next();
age=scan.nextInt();
year=scan.nextInt();
month=scan.nextInt();
day=scan.nextInt();
Sno=scan.next();
GPA=scan.nextDouble();
Student stu=new Student(name,ID,password,age,year,month,day,Sno,GPA);
m.Open(stu);
System.out.println("创建成功!");
}
break;
}
case 2:{
System.out.println("输入学生密码:");
password=scan.next();
int index=m.search(password);
if(index!=-1){
Student s=m.getItem(index);
m.Close(s);
System.out.println("此账号已销户!");
}
else{
System.out.println("此学生账户不存在!");
}
break;
}
case 3:{
System.out.println("输入学生密码:");
password=scan.next();
int index=m.search(password);
if(index!=-1){
Student s=m.getItem(index);
StringBuffer a=s.geta();
System.out.println("存取款信息:\n"+a);
}
else{
System.out.println("此学生账户不存在!");
}
break;
}
case 4:{
System.out.println("输入学生密码:");
password=scan.next();
int index=m.search(password);
if(index!=-1){
Student s=m.getItem(index);
System.out.print("输入存款金额:");
int money=scan.nextInt();
s.Deposit(money);
}
else{
System.out.println("此学生账户不存在!");
}
break;
}
case 5:{
System.out.println("输入学生密码:");
password=scan.next();
int index=m.search(password);
if(index!=-1){
Student s=m.getItem(index);
System.out.print("输入取款金额:");
int money=scan.nextInt();
s.Withdraw(money);
}
else{
System.out.println("此学生账户不存在!");
}
break;
}
default: System.exit(0);
}
}
}
}
3、
import java.util.*;
class Vehicle{
int wheels;//车轮数
String weight;//车重
Vehicle(int wheels,String weight){
this.wheels=wheels;
this.weight=weight;
}
}
class Car extends Vehicle{
int loader;//载人数
Car(int wheels,String weight,int loader){
super(wheels,weight);
this.loader=loader;
}
}
class Truck extends Car{
String payload;//载重量
Truck(int wheels,String weight,int loader,String payload){
super(wheels,weight,loader);
this.payload=payload;
}
}
class Hello{
public static void main(String args[]){
Scanner scan=new Scanner(System.in);
int wheels;
String weight;
int loader;
String payload;
int n;//车的数目
System.out.print("输入车的数量:");
n=scan.nextInt();
System.out.print("输入车的信息: 车轮数 车重 载人数 载重量");
for(int i=0;i<n;i++){
wheels=scan.nextInt();
weight=scan.next();
loader=scan.nextInt();
payload=scan.next();
System.out.println("输出车的相应信息:");
System.out.println("汽车: 车轮数 车重 "+wheels+" "+weight);
System.out.println("小车: 车轮数 车重 载人数 "+wheels+" "+weight+" "+loader);
System.out.println("卡车: 车轮数 车重 载人数 载重量 "+wheels+" "+weight+" "+loader+" "+payload);
}
}
}
4、
import java.util.*;
import java.lang.Math;
public interface Shape{
public abstract double getArea();
public abstract double getPerimeter();
}
class Coordinates{
long x;
long y;
Coordinates(long x,long y){
this.x=x;
this.y=y;
}
public void getPoints(){
System.out.println("("+x+","+y+")");
}
}
class Rectangle extends Coordinates implements Shape{
double side1;
double side2;
public double getArea(){
return side1*side2;
}
public double getPerimeter(){
return (side1+side2)*2;
}
Rectangle(double s1,double s2,long x,long y){
super(x,y);
side1=s1;
side2=s2;
}
}
class Circle extends Coordinates implements Shape{
double R;
Circle(double R,long x,long y){
super(x,y);
this.R=R;
}
public double getArea(){
double pi=Math.PI;
return pi*R*R;
}
public double getPerimeter(){
double pi=Math.PI;
return pi*R*2;
}
}
class Tritangle extends Coordinates implements Shape{
double s1;//三角形三条边
double s2;
double s3;
Tritangle(double s1,double s2,double s3,long x,long y){
super(x,y);
this.s1=s1;
this.s2=s2;
this.s3=s3;
}
public double getArea(){//海伦公式:用三个边长求三角形的面积
double p=(s1+s2+s3)/3;
return Math.sqrt(p*(p-s1)*(p-s2)*(p-s3));
}
public double getPerimeter(){
return s1+s2+s3;
}
}
class Hello{
public static void main(String args[]){
Scanner scan=new Scanner(System.in);
while(true){
System.out.println("输入数字:按1进入矩形 按2进入圆形 按3进入三角形 按其他数据则退出当前运算");
int n=scan.nextInt();
switch(n){
case 1:{
System.out.println("输入矩形的边长:");
double s1=scan.nextDouble();
double s2=scan.nextDouble();
System.out.print("输入矩形距离原点最近的点: ");
System.out.print("横坐标:");
long x=scan.nextLong();
System.out.print("纵坐标:");
long y=scan.nextLong();
Rectangle rec=new Rectangle(s1,s2,x,y);
System.out.println("矩形面积为:"+rec.getArea());
System.out.println("矩形周长为:"+rec.getPerimeter());
break;
}
case 2:{
System.out.println("输入圆的半径:");
double r=scan.nextDouble();
System.out.print("输入圆点横坐标:");
long x=scan.nextLong();
System.out.print("圆点纵坐标:");
long y=scan.nextLong();
Circle cir=new Circle(r,x,y);
Coordinates c=new Coordinates(x,y);
System.out.println("圆的面积为:"+cir.getArea());
System.out.println("圆的周长为:"+cir.getPerimeter());
System.out.println("圆点的坐标为:");c.getPoints();
break;
}
case 3:{
System.out.print("输入三角形三个顶点的坐标值:");
long x1=scan.nextLong();
long y1=scan.nextLong();
long x2=scan.nextLong();
long y2=scan.nextLong();
long x3=scan.nextLong();
long y3=scan.nextLong();
long x=0,y=0;
Coordinates c1=new Coordinates(x1,y1);
Coordinates c2=new Coordinates(x2,y2);
Coordinates c3=new Coordinates(x3,y3);
System.out.print("则三角形的三个顶点坐标分别为:");
c1.getPoints();c2.getPoints();c3.getPoints();
System.out.print("则三角形的三个边长d1、d2、d3分别为:");
double s1=scan.nextDouble();
double s2=scan.nextDouble();
double s3=scan.nextDouble();
Tritangle tri=new Tritangle(s1,s2,s3,x,y);
double S=tri.getArea();
System.out.println("三角形的面积为:"+S);
System.out.println("三角形的周长为:"+tri.getPerimeter());
System.out.println("d1对应的高为:"+(2*S/s1)+" d2对应的高为:"+(2*S/s2)+" d3对应的高为:"+(2*S/s3));
break;
}
default: System.exit(0);
}
}
}
}
5、
(1)
package Mypackage;
import java.util.*;
class Test_YMD{
private int year;
private int month;
private int day;
public Test_YMD(int year,int month,int day){
this.year=year;
this.month=(((month>=1)&&(month<=12))?month:1);
this.day=(((day>=1)&&(day<=31))?day:1);
}
public Test_YMD(){
this(0,0,0);
}
public int year(){
return year;
}
public static int thisyear(){
return Calendar.getInstance().get(Calendar.YEAR);
}
public String toString(){
return year+"-"+month+"-"+day;
}
public static void main(String args[]){
}
}
四、实验结果
1、
(1)输入违法数据,显示日期无效
(2)输入有效数据,判断日期是否是闰年以及大小月:
(3)完整输入十组学生信息,判断日期合法性:
2、
(1)最开始的:
(2)改善之后:
(3)最后结果: 具体过程: 首先选择创建学生用户人数:2 然后创建实例,输入两位学生信息,创建成功!
设置密码并且记住,在操作过程中我们通过密码来对相应同学进行存取款操作。
然后给“陈可新”同学存款300元,然后给“孙玉”同学取款20元,因为从未给孙玉同学存款过,其余额为0,取款失败。然后给“陈可新”同学取款50元,取款成功,证明刚才存款正确。然后再给“孙玉”同学存款200元。之后分别查询两位同学的存取款信息,信息无误,实验结果正确。最后对两位同学分别执行销户操作,然后按0退出当前页面。实验结束。
3、
4、
5、
(1)创建Mypackage包并且在包中创建类: 添加环境变量:
编译Test_YMD类之后将Test_JMD.class放入Mypackage包中。
(2)调用Mypackage包中的Test_YMD类,输出一个人的姓名、年龄、出生日期
五、实验总结分析
1、关于第一个实验:
(1)设置两个类:MyDate类和Student类,并且Student类设置为MyDate类的子类。在第一个Java基础程序设计实验中我声明了一个Student类,在这里拿过来略作变化:
原本的Student类直接使用字符串数组、整型数组和浮点型数组来输入十组学生信息,没有引用其他的类。但是在本实验中,我引用了java.util.ArrayList,ArrayList类是一个可以动态修改的数组,没有大小和长度的限制,声明并初始化一个数组:
ArrayList<类名> 对象名=new ArratList<>();
类名是指所创建数组中数据代表的属性所属的类。在本实验中,是指包含学生信息属性的Student类,其中声明了变量:name(学生姓名)、age(学生年龄)、score(学生Java实验成绩),这些都是Student类自己私有的,还有它从父类MyDate继承来的变量:year、month、day。
我还应用了ArrayList类的一些常用方法: add():添加元素 get():通过索引值获取元素
(2)根据本实验的目的获取需要实现的方法信息:a.判断学生信息中生日信息的合法性
b.(如果日期有效)判断年份是否是闰年,判断月份是大月还是小月或者都不是(是二月) c.依旧能够正常输入十组学生信息
根据以上分析,首先需要布尔类型的方法,分别判断是否是闰年,以及日期合法性:
注:1.今年是2022年,年份不得超过2022
2.闰年能被400整除或者能被4整除但不能被100整除然后还要一个能够返回十二个月份天数的方法来规定大小月:
2、关于第四个实验: (1)三角形: 我原本打算根据三个顶点坐来求三角形的面积和周长,以及三角形的三个边长,原理如下:
假设三角形三个顶点的坐标分别为:A(x1,y1)、B(x2,y2)、C(x2,y2),以AB边为底,求C点到线段AB的距离即为高。点到直线的距离公式为:
三角形面积用顶点坐标表示:
三角形周长用顶点坐标表示:
目前来看没有问题,但是当我运行的时候,却发现一个很严重的问题:
我所使用的Math.sqrt()(求平方值方法)以及Math.abs()(求绝对值方法)都是double数据类型,而根据Coordinates父类给出的构造函数,三角形顶点坐标都是long数据类型,由long转换成double会对结果有损害,因此编译错误,无法运行,这种方法行不通。
因此,我只能分别输入三角形的三个顶点坐标(long)和三条边长的值(double),根据边长来求三角形的面积和周长:
假设三条边长的值分别是:s1,s2,s3 三角形周长为:
三角形面积需要用到经典的由三角形边长求面积的公式:海伦公式。以下是对海伦公式的一个简单推导:如上图所示,三角形ABC中,得到如下方程:
所以
最后化简得到海伦公式:
用代码表示为:
(2)实验过程中发现了以下错误:
1.错误:无法将类中的构造器应用到以下类型 原因:实际参数列表与形式参数列表长度不同
我原本以为是因为没有设置无参构造方法,但是设置无参构造方法之后也仍然显示以上错误。后来发现是子类的构造方法中必须覆盖父类的构造方法:
父类的构造方法:
在父类的构造方法中包含了long数据类型的成员变量x和y,因此在子类的构造方法中也必须包含long数据类型的变量x和y,并且在构造方法的第一行调用super()(超类即父类):
而我当时一直没有发现的原因是虽然我改正了矩形类和圆形类,但是在三角形类中我想使用顶点坐标的值来求三角形的面积,因此我在Rectangle类中声明了如下变量:
Coordinates c1; Coordinates c2; Coordinates c3; 代表三角形的三个顶点。
对应Rectangle类的构造方法变成了:
这显然是不对的,但是我被我声明的c1、c2、c所迷惑了,因为有x1,x2,x3,y1,y2,y3,我就忘记了Coordinates父类中的x,y,所以才一直导致错误,修改错误之后就不再发生此类报错。
2.对super()的调用必须是构造方法总的第一个语句:
(3)圆形:
圆的面积和周长计算:π的表示方式 首先import java.lang.Math;
或者
两种都可以 (4)数据输出正常之后的数据改进: 以下图片是我之前得到的一次输出:
数据不完全正确(我当时写错了海伦公式,发现之后已经改正),重点是不必要的数据精度,不利于我观察实验数据,因此我限制了double类型的数据精度,只显示小数点后两位即可。
之后数据精度得到控制,我观察数据也方便了许多。
3、关于第二个实验: (1)在运行代码的过程中,对于查询功能,我想显示存取款信息的同时也显示相对应的学生信息。
但是在运行的过程中总是出现如下错误:(下图) 而且对于不同时刻存入的不同学生信息都是输出:Student@4554617c
并且在实验过程中我发现每一次进行编译成功进行执行时输入的学生信息以及存取款数据只能支持这一次的展示。在下一次执行程序时只能重新创建账户并进行一系列的操作,跟上一次毫无关联。
所以尽管我想要在查询时同时展示学生信息,但是学生信息在本次操作中仍然可以在创建账户的操作中查看。因此这是没有必要的,所以在最后的结果展示当中我放弃了显示学生信息。
(2)给我自己开户: