# JAVA 实验三:掌握泛型类的原理和使用方法
# 实验任务书
“实验 3 说明” 文件夹中给出了一些源程序,完成以下要求:其中,StuList.java(假设其中的类实现了接口 MyList)中需要补充代码。
要求:
(注意,本次实验要做两个版本。
第一个版本是,排序时树映射的第一个泛型是封装类,测试程序时,会发现这种版本在学生成绩都不相同时是没有问题的,如果有成绩相同的情况,请观察程序的显示结果,看看有什么问题?
第二个版本是,对于第一个版本解决不了的问题,请自己思考,编写第二个版本,使得有成绩相同的情况,也都可以正确显示。)
(1)假设源程序 StuList.java 中的类实现了接口 MyList,创建源程序 MyList.java,其中的内容是接口 MyList 的声明。
(2)在 StuList.java 中根据要求补充代码。其中,学生信息不再存放在数组中,而是存放在双链表泛型类的对象中;排序时不再使用冒泡法或者选择法排序,而是使用树映射泛型类的对象进行排序输出。
(4)StuList.java,MyList.java,Undergraduate.java,Postgraduate.java 和 Student.java 在同一个包中。Main.java 在无名包中。
上述源程序可以完成如下任务:
创建学生链表,使用者根据提示信息,选择从键盘上输入本科生或者研究生的学生信息,将其加入学生链表,添加学生信息,删除学生信息,显示学生信息,按照学生成绩排序等。
# 解决
# 第一个版本
# 项目文件结构
├── src (源文件夹)
│ ├── students (包)
│ ├── Student.java (学生信息类(抽象类))
│ ├── StuList.java (实现接口 MyList)
│ ├── MyList.java (接口)
│ ├── Undergraduat.java (本科生类)
│ └── Postgraduate.java (研究生类)
│ ├── Main.java (位于无名包下)
# Main.java
import student2.*; | |
import java.util.*; | |
public class Main | |
{ | |
public static void main(String[] args) | |
{ | |
Scanner in=new Scanner(System.in); | |
StuList list=new StuList(); // 创建学生链表 | |
int num; | |
System.out.println("要创建本科生信息表还是研究生信息表?\nA.本科生\tB.研究生"); | |
switch(in.next().charAt(0)) | |
{ | |
case 'A': | |
case 'a': | |
System.out.println("请问要输入多少个本科生的信息?"); | |
num=in.nextInt(); | |
for(int i=0;i<num;i++) | |
{ | |
System.out.println("请输入第"+(i+1)+"位学生的学号,姓名,数学、计算机成绩:"); | |
Student t=new Undergraduate(in.nextInt(),in.next(),in.nextDouble(),in.nextDouble()); | |
list.addStu(t); | |
} | |
list.addStu(new Undergraduate(1312,"shgd",99,98.5)); | |
list.addStu(new Undergraduate(1316,"ddsa",89,88.5)); | |
list.print(); | |
break; | |
case 'B': | |
case 'b': | |
System.out.println("请问要输入多少个研究生的信息?"); | |
num=in.nextInt(); | |
for(int i=0;i<num;i++) | |
{ | |
System.out.println("请输入第"+(i+1)+"位学生的学号,姓名,数学、计算机成绩,导师和研究方向:"); | |
Student t=new Postgraduate(in.nextInt(),in.next(),in.nextDouble(),in.nextDouble(),in.next(),in.next()); | |
list.addStu(t); | |
} | |
list.addStu(new Postgraduate(1312,"shgd",99,98.5,"xyy","os")); | |
list.addStu(new Postgraduate(1316,"ddsa",89,88.5,"wcl","rgzn")); | |
list.print(); | |
break; | |
default: | |
System.out.println("输入错误!!!"); | |
break; | |
} | |
System.out.println("是否需要删除某个学生信息?输入y确定,输入其他继续:"); | |
String words=in.next(); | |
if(words.equals("Y")||words.equals("y")) | |
{ | |
System.out.println("删除第几个同学?"); | |
list.removeStu(in.nextInt()); | |
System.out.println("最新的学生信息为:"); | |
list.print(); | |
list.sort(1); | |
list.sort(2); | |
in.close(); | |
} | |
else | |
{ | |
System.out.println("最新的学生信息为:"); | |
list.print(); | |
list.sort(1); | |
list.sort(2); | |
in.close(); | |
} | |
} | |
} |
# Student.java
package student2; | |
public abstract class Student | |
{ | |
int id; | |
String name; | |
double mathScore; | |
double computerScore; | |
public Student(int id,String name,double mathScore,double computerScore) | |
{ | |
this.id=id; | |
this.name=name; | |
this.mathScore=mathScore; | |
this.computerScore=computerScore; | |
} | |
public int getId() | |
{ | |
return id; | |
} | |
public void setId(int id) | |
{ | |
this.id = id; | |
} | |
public String getName() | |
{ | |
return name; | |
} | |
public void setName(String name) | |
{ | |
this.name = name; | |
} | |
public double getMathScore() | |
{ | |
return mathScore; | |
} | |
public void setMathScore(double mathScore) | |
{ | |
this.mathScore = mathScore; | |
} | |
public double getComputerScore() | |
{ | |
return computerScore; | |
} | |
public void setComputerScore(double computerScore) | |
{ | |
this.computerScore = computerScore; | |
} | |
public abstract void print(); | |
} |
# StuList.java
package student2; | |
import java.util.*; | |
public class StuList implements MyList | |
{ | |
LinkedList<Student> list; // 使用双链表泛型类对象存储学生信息 | |
public StuList() | |
{ | |
list=new LinkedList<Student>(); | |
} | |
public int size() | |
{ | |
return list.size(); | |
} | |
public boolean addStu(Student x) // 添加学生信息 | |
{ | |
return list.add(x); | |
} | |
public Student removeStu(int index) // 删除指定位置的学生信息 | |
{ | |
return list.remove(index-1); | |
} | |
public void clear() | |
{ | |
list.clear(); | |
} | |
public void sort(int x) | |
{ | |
TreeMap<Double, Student>stuMap=new TreeMap<Double, Student>(); | |
Iterator<Student>iter=list.iterator(); | |
if(x==1) // 按数学成绩排序 | |
{ | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
stuMap.put(temp.getMathScore(),temp); | |
} | |
System.out.println("数学成绩从低到高排序为:"); | |
} | |
else if(x==2) // 按计算机成绩排序 | |
{ | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
stuMap.put(temp.getComputerScore(),temp); | |
} | |
System.out.println("计算机成绩从低到高排序为:"); | |
} | |
Collection<Student>collection=stuMap.values(); | |
iter=collection.iterator(); | |
System.out.printf("共有%d名学生,信息如下:%n",stuMap.size()); | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
temp.print(); | |
} | |
} | |
public void print() | |
{ | |
System.out.printf("共有%d名学生,信息如下:%n",list.size()); | |
Iterator<Student>iter=list.iterator(); | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
temp.print(); | |
} | |
} | |
} |
# MyList.java
package student2; | |
interface MyList { | |
public int size(); | |
public boolean addStu(Student x); | |
public Student removeStu(int index); | |
public void clear(); | |
public void sort(int x); | |
public void print(); | |
} |
# Undergraduat.java
package student2; | |
public class Undergraduate extends Student | |
{ | |
public Undergraduate(int id,String name,double mathScore,double computerScore) | |
{ | |
super(id,name,mathScore,computerScore); | |
} | |
public void print() | |
{ | |
System.out.printf("学号:%8d\t姓名:%8s\t数学成绩:%.1f\t计算机成绩:%.1f%n",getId(),getName(),getMathScore(),getComputerScore()); | |
} | |
} |
# Postgraduate.java
package student2; | |
public class Postgraduate extends Student | |
{ | |
public String tutor; | |
public String researchArea; | |
public Postgraduate(int id,String name,double mathScore,double computerScore,String tutor,String area) | |
{ | |
super(id,name,mathScore,computerScore); | |
this.tutor=tutor; | |
this.researchArea=area; | |
} | |
public void print() | |
{ | |
System.out.printf("学号:%8d\t姓名:%8s\t数学成绩:%.1f\t计算机成绩:%.1f\t导数姓名:%8s\t研究方向:%8s%n",getId(),getName(),getMathScore(),getComputerScore(),getTutor(),getResearchArea()); | |
} | |
public String getTutor() | |
{ | |
return tutor; | |
} | |
public void setTutor(String tutor) | |
{ | |
this.tutor = tutor; | |
} | |
public String getResearchArea() | |
{ | |
return researchArea; | |
} | |
public void setResearchArea(String researchArea) | |
{ | |
this.researchArea = researchArea; | |
} | |
} |
# 第二个版本
- 只需要改
StuList.java
# Stulist.java (改)
package student2; | |
import java.util.*; | |
class Key implements Comparable<Object> // 新添加的类 Key | |
{ | |
double num=0; | |
Key(double num) | |
{ | |
this.num=num; | |
} | |
public int compareTo(Object b) | |
{ | |
Key t=(Key)b; | |
if(this.num == t.num) | |
return 1; | |
else | |
return (int)((this.num-t.num)*10); | |
} | |
} | |
public class StuList implements MyList | |
{ | |
LinkedList<Student> list; // 使用双链表泛型类对象存储学生信息 | |
public StuList() | |
{ | |
list=new LinkedList<Student>(); | |
} | |
public int size() | |
{ | |
return list.size(); | |
} | |
public boolean addStu(Student x) // 添加学生信息 | |
{ | |
return list.add(x); | |
} | |
public Student removeStu(int index) // 删除指定位置的学生信息 | |
{ | |
return list.remove(index-1); | |
} | |
public void clear() | |
{ | |
list.clear(); | |
} | |
public void sort(int x) | |
{ | |
//TreeMap<Double, Student>stuMap=new TreeMap<Double, Student>(); // 原来 | |
TreeMap<Key, Student>stuMap=new TreeMap<Key, Student>(); // 改后 | |
Iterator<Student>iter=list.iterator(); | |
if(x==1) // 按数学成绩排序 | |
{ | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
//stuMap.put (temp.getMathScore (),temp); // 原来 | |
stuMap.put(new Key(temp.getMathScore()),temp); // 改后 | |
} | |
System.out.println("数学成绩从低到高排序为:"); | |
} | |
else if(x==2) // 按计算机成绩排序 | |
{ | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
//stuMap.put (temp.getComputerScore (),temp); // 原来 | |
stuMap.put(new Key(temp.getComputerScore()),temp); // 改后 | |
} | |
System.out.println("计算机成绩从低到高排序为:"); | |
} | |
Collection<Student>collection=stuMap.values(); | |
iter=collection.iterator(); | |
System.out.printf("共有%d名学生,信息如下:%n",stuMap.size()); | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
temp.print(); | |
} | |
} | |
public void print() | |
{ | |
System.out.printf("共有%d名学生,信息如下:%n",list.size()); | |
Iterator<Student>iter=list.iterator(); | |
while(iter.hasNext()) | |
{ | |
Student temp=iter.next(); | |
temp.print(); | |
} | |
} | |
} |
# 实验报告
# 实验目的
掌握泛型类的原理和使用方法
# 实验内容
“实验 3 说明” 文件夹中给出了一些源程序,完成以下要求:其中,StuList.java(假设其中的类实现了接口 MyList)中需要补充代码。
要求:
(注意,本次实验要做两个版本。
第一个版本是,排序时树映射的第一个泛型是封装类,测试程序时,会发现这种版本在学生成绩都不相同时是没有问题的,如果有成绩相同的情况,请观察程序的显示结果,看看有什么问题?
第二个版本是,对于第一个版本解决不了的问题,请自己思考,编写第二个版本,使得有成绩相同的情况,也都可以正确显示。)
(1)假设源程序 StuList.java 中的类实现了接口 MyList,创建源程序 MyList.java,其中的内容是接口 MyList 的声明。
(2)在 StuList.java 中根据要求补充代码。其中,学生信息不再存放在数组中,而是存放在双链表泛型类的对象中;排序时不再使用冒泡法或者选择法排序,而是使用树映射泛型类的对象进行排序输出。
(4)StuList.java,MyList.java,Undergraduate.java,Postgraduate.java 和 Student.java 在同一个包中。Main.java 在无名包中。
上述源程序可以完成如下任务:
创建学生链表,使用者根据提示信息,选择从键盘上输入本科生或者研究生的学生信息,将其加入学生链表,添加学生信息,删除学生信息,显示学生信息,按照学生成绩排序等。
# 实验结果
# 第一个版本

# 第二个版本

# 实验分析
1、由图可知,第一个版本中,如果出现学生成绩相同的情况下,只会保留一个人的成绩,其他成绩相同的人的成绩都会消失。第二个版本修复了这个问题。
2、用到了 LinkedList 和 TreeMap<K,V> 两个泛型类,其中利用 LinkedList list = new LinkedList (); 创建双链表泛型类对象 list 存储学生信息。
利用 Double 封装类,通过 TreeMap 是按键(学生的成绩)的升序排列。TreeMap<Double,Student>treemap=new TreeMap<Double,Student>()。但当学生成绩出现重复时,让 Key 类实现 Comparable 接口重写 CompareTo()方法。
TreeMap<Key,Student> treemap= new TreeMap<Key,Student>(); 实现重复成绩的学生不会被删除。3. 对 Comparable 和 Comparator 接口的区别和用法不太理解。
Comparable 接口(排序接口)仅仅只包括一个函数,定义如下:
package java.lang; import java.util.*; public interface Comparable { public int compareTo(T o);}// 通过 x.compareTo (y) 来 “比较 x 和 y 的大小”。若返回 “负数”,意味着 “x 比 y 小”;返回 “零”,意味着 “x 等于 y”;返回 “正数”,意味着 “x 大于 y”.//Comparator 接口(比较器)仅仅只包括两个函数,定义如下: package java.util; public interface Comparator { int compare(T o1, T o2); boolean equals(Object obj);}
int compare(T o1, T o2)是 “比较 o1 和 o2 的大小”。返回 “负数”,意味着 “o1 比 o2 小”;返回 “零”,意味着 “o1 等于 o2”;返回 “正数”,意味着 “o1 大于 o2”, 若一个类要实现 Comparator 接口:它一定要实现 compareTo (T o1, T o2) 函数。
即:Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。. 而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器。