本文最后更新于2020年11月10日,已超过 3 个月没更新!

JAVA实验二:掌握继承与接口的原理和使用方法

实验任务书

根据“实验2说明”文件夹中给出的源程序Main.java,StuGroup.java(假设其中的类实现了接口MyGroup),Student.java(其中的类Student是抽象类, print( )方法是抽象方法)。
要求:
(1)创建源程序MyGroup.java,其中的内容是接口MyGroup的声明。
(2)创建源程序Undergraduate.java,其中的类Undergraduate继承源程序Student.java中的抽象类Student,实现其中的抽象方法print( )。
(3)创建源程序Postgraduate.java,其中的类Postgraduate继承源程序Student.java中的抽象类Student,实现其中的抽象方法print( ),并且,在父类的基础上增加两个新的属性:导师和研究方向。
(4)StuGroup.java,MyGroup.java,Undergraduate.java,Postgraduate.java和Student.java在同一个包中。Main.java在无名包中。
(5)在程序中做出注释,哪些地方是上转型?哪些地方体现了运行时多态?
上述源程序可以完成如下任务:
使用者根据提示信息,选择从键盘上输入本科生或者研究生的学生信息,可以添加学生信息、删除学生信息、显示学生信息、按照学生成绩排序等。

解决

项目文件结构

├── src  (源文件夹)
│   ├── students  (包)
│       ├── Student.java  (学生信息类(抽象类))
│       ├── StuGroup.java  (实现接口 MyGroup)
│       ├── MyGroup.java  (接口)
│       ├── Undergraduat.java  (本科生类)
│       └── Postgraduate.java  (研究生类)
│   ├── Main.java (位于无名包下)

Main.java

import students.*;
import java.util.*;
public class Main
{
    public static void main(String[] args)
    {
        Scanner in=new Scanner(System.in);
        StuGroup group=new StuGroup(20);  //group可以容纳20个学生
        int num;  //实际输入的学生信息
        System.out.println("要创建本科生信息表还是研究生信息表?\nA.本科生\tB.研究生");
        Scanner reader = new Scanner(System.in);
        char choice = reader.next().charAt(0);//charAt(index)用于返回索引处的字符
        switch(choice)
        {
        case 'A':
        case 'a':
            System.out.println("请问要输入多少个本科生的信息?");
            num = reader.nextInt();
            Student stuB[] = new Undergraduate[num];//stuB[]对象数组是子类Undergraduate对象的上转型对象
            for(int i=0;i<num;i++)
            {
                System.out.println("请输入第"+(i+1)+"位学生的学号,姓名,数学、计算机成绩");
                stuB[i] = new Undergraduate(reader.nextInt(), reader.next(),reader.nextDouble(), reader.nextDouble());//从键盘输入学生信息,并赋值给学生
                group.addStu(stuB[i]);//参数为引用类型
            }
            group.addStu(new Undergraduate(1312,"shgd",99,98.5));
            group.addStu(new Undergraduate(1316,"ddsa",89,88.5));
            System.out.println("添加后所有本科生的信息为:");
            group.print();
            break;
        case 'B':
        case 'b':
            System.out.println("请问要输入多少个研究生的信息?");
            num = reader.nextInt();
            Student[] stuY = new Postgraduate[num];  //stuY[]对象数组是子类Postgraduate对象的上转型对象
            for(int i=0;i<num;i++)
            {
                System.out.println("请输入第"+(i+1)+"位学生的学号,姓名,数学、计算机成绩,导师和研究方向,以空格隔开");
                stuY[i] = new Postgraduate(reader.nextInt(), reader.next(),reader.nextDouble(), reader.nextDouble(),reader.next(),reader.next());
                group.addStu(stuY[i]);
            }
            group.addStu(new Postgraduate(1312,"shgd",99,98.5,"xyy","os"));//与本科生对比体现运行时的多态性
            group.addStu(new Postgraduate(1316,"ddsa",89,88.5,"wcl","rgzn"));
            System.out.println("添加后所有研究生信息为:");
            group.print();
            break;
        default:
            System.out.println("输入错误!!!");
            break;
        }
        System.out.println("是否需要删除某个学生信息?输入y确定,输入其他继续:");
        String words=reader.next();
        if(words.equals("Y")||words.equals("y"))
        {
            System.out.println("删除第几个同学?");
            group.removeStu(reader.nextInt());
            System.out.println("最新的学生信息为:");
            group.print();
            group.sort(1);
            group.print();//按照数学成绩排序后输出
            group.sort(2);
            group.print();//按照计算机成绩排序后输出
            in.close();
        }
        else
        {
            System.out.println("最新的学生信息为:");
            group.print();
            group.sort(1);
            group.print();//按照数学成绩排序后输出
            group.sort(2);
            group.print();//按照计算机成绩排序后输出
            in.close();
        }
    }
}

Student.java

package students;

public abstract class Student
{
    int num;
    String name;
    double mathscore;
    double computerscore;
    Student(int num,String name,double mathscore,double computerscore)
    {
        this.num=num;
        this.name=name;
        this.mathscore=mathscore;
        this.computerscore=computerscore;
    }

    //学号
    public void getnum(int num)
    {
        this.num=num;
    }
    public int setnum()
    {
        return this.num;
    }

    //姓名
    public void getname(String name)
    {
        this.name=name;
    }
    public String setname()
    {
        return this.name;
    }

    //数学成绩
    public void getmath(double mathscore)
    {
        this.mathscore=mathscore;
    }
    public double setmath()
    {
        return mathscore;
    }

    //计算机成绩
    public void getcomputer(double computerscore)
    {
        this.computerscore=computerscore;
    }
    public double setcomputer()
    {
        return computerscore;
    }

    abstract void print();
}

StuGroup.java

package students;

public class StuGroup implements MyGroup //StuGroup实现了MyGroup接口
{
     private Student[] stu;
     private int length;   //实际容量

    public StuGroup(int len)
    {
        stu=new Student[len];
    }

    private boolean isOverflow()    //辅助方法,判断数组是否溢出
    {
        if(this.length<stu.length)
            return false;
        else
            return true;
    }

    public boolean isEmpty()    //判断数组是否为空
    {
        return this.length==0;
    }

    public boolean addStu(Student x)  //添加学生信息
    {
        if(isOverflow())
            return false;
        stu[length++]=x;
        return true;
    }

    public Student removeStu(int index)  //删除指定位置的学生信息
    {
        if(isEmpty())
        {
            System.out.println("学生表空的~~~删除失败~~~~");
            return null;
        }
        Student temp=stu[index-1];
        for(int i=index-1;i<this.length-1;i++)
        {
            stu[i]=stu[i+1];
        }
        this.length--;
        return temp;
    }

    public void sort(int x)   //按照成绩排序,参数1按数学排序,参数2按计算机排序
    {
        if(x==1)
        {
            for(int i =0;i<length-1;i++)
                for(int j =0;j<length-i-1;j++)//冒泡排序
                {
                    if(stu[j].setmath()<stu[j+1].setmath())
                    {
                        Student temp;//声明一个对象(引用),用于交换
                        temp =stu[j+1];
                        stu[j+1] = stu[j];
                        stu[j] = temp;
                    }
                }
            System.out.println("按数学成绩降序排列为:");
        }
        else if(x==2)
        {
            for(int i =0;i<length-1;i++)
                for(int j =0;j<length-i-1;j++)
                {
                    if(stu[j].setcomputer()<stu[j+1].setcomputer())
                    {
                        Student temp;
                        temp =stu[j+1];
                        stu[j+1] = stu[j];
                        stu[j] = temp;
                    }
                }
            System.out.println("按计算机成绩降序排名:");
        }
     }

    public void print()
    {
        for(int i =0;i<length;i++)
            stu[i].print();//调用Student子类的print()方法
    }

}

MyGroup.java

package students;

public interface MyGroup {
    boolean addStu(Student x);
    Student removeStu(int index);
    void sort(int x);
}

Undergraduat.java

package students;

public class Undergraduate extends Student {

    public Undergraduate(int num, String name, double mathscore, double computerscore) {
        super(num, name, mathscore, computerscore);
        // TODO 自动生成的构造函数存根
    }
    void print() {
        System.out.println("本科生信息:"+"学号:"+setnum()+" ,姓名:"+setname()+" ,数学成绩:"+setmath()+" ,计算机成绩:"+setcomputer());
    }

}

Postgraduate.java

package students;

public class Postgraduate extends Student {
    String teacher;
    String direction;
    public Postgraduate(int num, String name, double mathscore, double computerscore, String teacher, String direction) {
        super(num, name, mathscore, computerscore);
        this.teacher = teacher;
        this.direction = direction;
    }

    void getTeacher(String teacher)
    {
        this.teacher =teacher;
    }
    String setTeacher()
    {
        return this.teacher;
    }
    void getDirection(String direction)
    {
        this.direction =direction;
    }
    String setDirection()
    {
        return this.direction;
    }

    void print() {
        System.out.println("研究生学生信息为:"+"学号:"+setnum()+",姓名:"+setname()+",数学成绩:"+setmath()+",计算机成绩:"+setcomputer()+"导师:"+setTeacher()+",研究方向:"+setDirection());  
    }

}

实验报告

实验目的

掌握继承与接口的原理和使用方法。

实验内容

根据“实验2说明”文件夹中给出的源程序Main.java,StuGroup.java(假设其中的类实现了接口MyGroup),Student.java(其中的类Student是抽象类, print( )方法是抽象方法)。

要求:

(1)创建源程序MyGroup.java,其中的内容是接口MyGroup的声明。

(2)创建源程序Undergraduate.java,其中的类Undergraduate继承源程序Student.java中的抽象类Student,实现其中的抽象方法print( )。

(3)创建源程序Postgraduate.java,其中的类Postgraduate继承源程序Student.java中的抽象类Student,实现其中的抽象方法print( ),并且,在父类的基础上增加两个新的属性:导师和研究方向。

(4)StuGroup.java,MyGroup.java,Undergraduate.java,Postgraduate.java和Student.java在同一个包中。Main.java在无名包中。

(5)在程序中做出注释,哪些地方是上转型?哪些地方体现了运行时多态?

上述源程序可以完成如下任务:

使用者根据提示信息,选择从键盘上输入本科生或者研究生的学生信息,可以添加学生信息、删除学生信息、显示学生信息、按照学生成绩排序等。

实验结果

  1. 本科生,有删除信息

imgbed.cn图床

  1. 本科生,无删除信息

imgbed.cn图床

  1. 研究生,有删除信息

imgbed.cn图床

  1. 研究生,无删除信息

imgbed.cn图床

实验分析

1、接口Interface

在这次实验中,MyGroup是接口,接口是一个抽象类型,是抽象方法的集合。类通过继承接口的方式,从而来继承接口的抽象方法。在MyGroup接口中,定义了addStu()增加学生信息函数、Student类方法removeStu()删除学生信息类的函数和sort()排序函数。

接口中每一个方法是隐式抽象的,接口中的方法会被隐式的指定为 public abstract,所以其他类引入接口时,只需要implements接口,而这个类能实现接口中的方法。

2、上转型

上转型和下转型都是父类和子类之间对象的转换,上转型是通过子类对象(小范围)实例化父类对象(大范围),在本次实验中体现上转型的是:

switch(choice)
        {
        case 'A':
        case 'a':
            System.out.println("请问要输入多少个本科生的信息?");
            num = reader.nextInt();
            Student stuB[] = new Undergraduate[num];//stuB[]对象数组是子类Undergraduate对象的上转型对象

这里Student stuB[] = new Undergraduate[num]; stuB[]对象数组是子类Undergraduate对象的上转型对象,Student是父类,Undergraduate是子类,通过父类定义一个对象,子类新建一个内存空间实例化父类的这个对象。

3、运行时多态

运行时多态的三个条件是

(1)、要有继承;

(2)、要有重写;

(3)、父类引用指向子类对象。

这里学生类的子类有两个,本科生和研究生,研究生类比本科生类多两个属性,因此在实现接口的方法(例如addStu()增加学生信息函数体现多态)

Student stuB[] = new Undergraduate[num];
for(int i=0;i<num;i++)
            {
                System.out.println("请输入第"+(i+1)+"位学生的学号,姓名,数学、计算机成绩");
                stuB[i] = new Undergraduate(reader.nextInt(), reader.next(),reader.nextDouble(), reader.nextDouble());//从键盘输入学生信息,并赋值给学生
                group.addStu(stuB[i]);//参数为引用类型
            }
            group.addStu(new Undergraduate(1312,"shgd",99,98.5));
            group.addStu(new Undergraduate(1316,"ddsa",89,88.5));

对比研究生如下:

Student[] stuY = new Postgraduate[num];
for(int i=0;i<num;i++)
            {
                System.out.println("请输入第"+(i+1)+"位学生的学号,姓名,数学、计算机成绩,导师和研究方向,以空格隔开");
                stuY[i] = new Postgraduate(reader.nextInt(), reader.next(),reader.nextDouble(), reader.nextDouble(),reader.next(),reader.next());
                group.addStu(stuY[i]);
            }
            group.addStu(new Postgraduate(1312,"shgd",99,98.5,"xyy","os"));
            group.addStu(new Postgraduate(1316,"ddsa",89,88.5,"wcl","rgzn"));

Undergraduate类和Postgraduate类都是Student的子类,可以看出上述函数Student父类分别定义两个对象,子类对象上转型到父类对象,使得addStu()函数添加的对象个数根据子类不同而不同。本科生类中,有四个属性,研究生六个属性,完美实现这个函数。

实验总结

1、接口是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。

2、上转型: 通过子类对象实例化父类对象。

优点:提高了代码的简洁性。

语法规则:<父类型> <引用变量名> = new <子类型>();

此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法。此时通过父类引用变量无法调用子类特有的方法。

3、运行时多态:

运行时多态的三个条件是

(1)、要有继承;

(2)、要有重写;

(3)、父类引用指向子类对象。

优点:提高了代码的扩展性,前期定义的代码可以使用后期的内容。

缺点:前期定义的内容不能调用后期子类的特有方法,调用的只能是父类。但如果是继承子类覆盖了父类方法,多态调用的仍是子类的方法

  • 最后由lavender编辑于2020年11月15日下午8:44

疏影横斜水清浅,暗香浮动月黄昏