[ Java学习 ] 泛型类的应用实验

成文原因:

这篇文章是我这周所做的 Java 实验题的一个小总结。

这次实验让我深刻赞同了我们 Java 老师在这节实验课前告诉我们的话:

最重要的是把问题想明白,它要怎么拆分成几个类,每个类里究竟需要哪些方法,具体细节怎么实现。当你真正把这些问题想清楚了以后,剩下的编程,其实就是很简单的事情了。难度往往不是难在编程,而是分解问题为一个个小问题后,逐一解决它们的能力。

  做完实验以后再来看老师这句话,觉得不能同意更多。

  我贴上来的代码有两份。

  前一份是未完成的代码,之所以未完成,是因为:写到一半时,觉得这样的结构设计太不合理了,如果照着这么写下去,会有许多重复的代码片段不断地出现,于是就想着这么去改进…怎样才能尽可能减少方法,但是提高代码的复用性呢?

  于是,果断放弃了前一种没写完的,不太优的结构,第二份代码才是写完时真正提交的最终版本。

  除了代码,我把实验报告的心得部分也一并贴了上来用以自警

-------------------------------下面是实验题目------------------------------

 

 

-------------------------------下面是代码------------------------------

/*
  前一份是未完成的代码,之所以未完成,是因为:写到一半时,觉得这样的结构设计太不合理了,如果照着这么写下去,会有许多重复的代码片段不断地出现,于是就想着这么去改进…怎样才能尽可能减少方法,但是提高代码的复用性呢?

  于是,果断放弃了前一种没写完的,不太优的结构,第二份代码才是写完时真正提交的最终版本。

*/

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.*;
class Customer
{
	private String name;
	private String fNum; // flight number,表示他所定的航线的航线号
	private int sum; //买了多少票
	
	Customer()
	{
	}
	
	Customer(String n, String f, int s)
	{
		name = n;
		fNum = f;
		sum = s;
	}
	
	public void setName(String n)
	{
		name = n;
	}
	
	public String getName()
	{
		return name;
	}
	
	public void setSum(int s)
	{
		sum = s;
	}
	
	public int getSum()
	{
		return sum;
	}
	
	public void setfNum(String f)
	{
		fNum = f;
	}
	
	String getfNum()
	{
		return fNum;
	}
}

class Flight
{
	private static int sum = 0; //航线计数
	private int order; //航线排列号
	private String destination;//终点站名
	private String FNum; //航班号
	private int limit; //乘客限额
	private int free; //余票数量
	private LinkedList<Customer> booked; //已预定客户列表
	private LinkedList<Customer> waiting; //等候替补客户名单
	
	Flight()
	{
		
	}
	
	Flight(int o, String d, String F, int l)
	{
		order = o;
		destination = d;
		FNum = F;
		limit = l;
	}
	
	public int getOrder()
	{
		return order;
	}
	
	public String getDestination()
	{
		return destination;
	}
	
	public String getFNum()
	{
		return FNum;
	}
	
	public int getLimit()
	{
		return limit;
	}
	
	public int getFree()
	{
		return free;
	}
	
	public void addFree(int f)
	{
		free += f;
	}
	
	public void subFree(int f)
	{
		free -= f;
	}
	
	public LinkedList<Customer> getBooked()
	{
		return booked;
	}
	
	public LinkedList<Customer> getWaiting()
	{
		return waiting;
	}
	
	public void showInfo() //show information
	{
		System.out.println("航线排列号为:" + order + " 终点站为:" + destination);
		System.out.println("航班号为:" + FNum + " 成员定额为: " + limit + " 剩余票数为: " + free);
		System.out.println("已订票客户有:");
		
		Iterator<Customer> it = booked.iterator();
		for (; it.hasNext(); )
		{
			System.out.println(it.next().getName() + " ");
		}
		System.out.println();
		System.out.println("等候替补客户有:");
		for ( it = waiting.iterator(); it.hasNext(); )
		{
			System.out.println(it.next().getName() + " ");
		}
		System.out.println();
	}
}

class Menu
{
	private ArrayList<Flight> flights;
	Flight temp;
	
	public void init()
	{
		Flight f = new Flight(1, "北京","K2", 20);
		flights.add(f);
		f = new Flight(2, "北京","K3", 23);
		flights.add(f);
		f = new Flight(3, "成都","K4", 25);
		flights.add(f);
	}
	
	public void addFlight(Flight flight) //加入一条航线
	{
		flights.add(flight);
	}
	
	public void query() //查询
	{
		Scanner in = new Scanner(System.in);
		int order = in.nextInt(); //次序
		Flight temp;
		
		Iterator<Flight> it = flights.iterator();
		
		for ( ; it.hasNext(); )
		{
			temp = it.next();
			if (temp.getOrder() == order)
			{
				temp.showInfo();
				return;
			}
		}				
		System.out.println("没有检索到相关信息");	
	}
	
	public void book() //订票
	{
		System.out.println("请输入航班号,您的姓名,以及您想要订购的票数");
		Scanner in = new Scanner(System.in);
		Flight temp;
		
		String tp, tp1; //tp 为航班号,tp1为姓名
		int tem; // temporary
		
		tp = in.next();
		tp1 = in.nextLine();
		tem = in.nextInt();
		
		
		Customer c = new Customer(tp1, tp, tem); //构造函数参数依次为:姓名、 航线号、 所购票数
		Iterator<Flight> it = flights.iterator();

		Flight temp;
		
		for ( ; it.hasNext(); )
		{
			temp = it.next();
			if (temp.getFNum() == tp)
			{
				if (temp.getFree() >= tem)
				{
					temp.subFree(tem);
					temp.getBooked().add(c);
					System.out.println("购票成功");
				}
				else
				{
					temp.getWaiting().add(c);
					System.out.println("抱歉,票数暂时不够!");
				}
				return;
			}
		}
		
		 System.out.println("输入的航线不存在!");
		
		
	}
	
	public void cancel() //退票
	{
		System.out.println("请输入航班号,您的姓名,以及您想要退票的票数");
		Scanner in = new Scanner(System.in);
		Flight temp;
		
		String tp, tp1; //tp 为航班号,tp1为姓名
		int tem; // temporary
		
		tp = in.next();
		tp1 = in.nextLine();
		tem = in.nextInt();

		Iterator<Flight> it = flights.iterator();

		Flight temp;
		
		for ( ; it.hasNext(); )
		{
			temp = it.next();
			if (temp.getFNum() == tp) //确认航班号确实存在
			{
				for ( Iterator<Customer> it2= temp.getBooked().iterator(); it2.hasNext();  )
				{
					Customer now = it2.next();
					if (now.getName() == tp1 && now.getfNum() == tp) //确认该顾客确实定了该航班的机票
					{
						temp.addFree(tem);
						System.out.println("退票成功");
						if (now.getSum() == tem) //如果顾客将自己买的票全部退票,则从买票列表删除该顾客
							temp.getBooked().remove(now);	
					}
				}
				
				for ( Iterator<Customer> it2= temp.getWaiting().iterator(); it2.hasNext();  ) //遍历该航班的waiting列表,看是否有满足条件的购票请求可以满足
				{
					Customer now = it2.next();
					if (now.getSum() <= temp.getFree())
				}
			}
		}
		
		 System.out.println("输入信息有误");
	}
	
	public void menu() //显示菜单
	{
		System.out.println("----------");
		System.out.println("1.航线查询"); 
		System.out.println("2.办理退票");
		System.out.println("3.办理退票");
		System.out.println("4.退出系统");
		System.out.println("----------");
		
		Scanner in = new Scanner(System.in);
		int order = in.nextInt(); //指令
		
		switch(order)
		{
		case 1: query(); break;
		case 2: book(); break;
		case 3: cancel(); break;
		case 4: System.exit(0); in.close();break;
		default: System.out.println("输入错误,请 重新运行订票系统!");
		}
		menu();
	}
}

public class test 
{
	
	public static void main(String args[] )
	{
		Menu m = new Menu();
		m.menu();
	}

}

//这份才是真正完整的,也是我提交的最终版本
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.*;
class Customer
{
	private String name;
	private String fNum; // flight number,表示他所定的航线的航线号
	private int sum; //买了多少票
	
	Customer()
	{
	}
	
	Customer(String n, String f, int s)
	{
		name = n;
		fNum = f;
		sum = s;
	}
	
	public String getName()
	{
		return name;
	}
	
	public int getSum()
	{
		return sum;
	}
	
	public String getfNum()
	{
		return fNum;
	}
	
	public void setSum(int s)
	{
		sum = s;
	}
}

class Flight
{
	private static int sum = 0; //航线计数
	private int order; //航线排列号
	private String destination;//终点站名
	private String FNum; //航班号
	private int limit; //乘客限额
	private int free; //余票数量
	private LinkedList<Customer> booked; //已预定客户列表
	private LinkedList<Customer> waiting; //等候替补客户名单
	
	Flight()
	{
		
	}
	
	Flight(int o, String d, String F, int l)
	{
		order = o;
		destination = d;
		FNum = F;
		limit = free = l;
		booked = new LinkedList<Customer>();
		waiting = new LinkedList<Customer>();
	}
	
	public String getDestination()
	{
		return destination;
	}
	
	public String getFNum()
	{
		return FNum;
	}
	
	public void showInfo() //show information
	{
		System.out.println("航线排列号为:" + order + " 终点站为:" + destination);
		System.out.println("航班号为:" + FNum + " 成员定额为: " + limit + " 剩余票数为: " + free);
		System.out.println();
		System.out.println("已订票客户有:");
		
		Iterator<Customer> it = booked.iterator();
		for (; it.hasNext(); )
		{
			System.out.println(it.next().getName() + " ");
		}
		System.out.println();
		System.out.println("等候替补客户有:");
		for ( it = waiting.iterator(); it.hasNext(); )
		{
			System.out.println(it.next().getName() + " ");
		}
		System.out.println();
	}
	
	public void isbook(Customer c)
	{
		
		if (c.getSum() > free) //检验是否有足够余票可供该顾客订票
		{
			System.out.println("抱歉,票数暂时不足!");
			waiting.add(c);
			return;
		}
		
		book(c); //先判断可不可以订票,确认可以再订票
	}
	
	public void book(Customer c) //这个函数可重用,在退票以后,遍历 waiting 链表之前
	{
		for (Iterator<Customer> it = booked.iterator();  it.hasNext(); ) //判断该顾客之前是否有订过该航班的票
		{
			Customer now = it.next();
			if (now.getName().equals(c.getName()))
			{
				now.setSum(now.getSum() + c.getSum());
				free -= c.getSum();
				System.out.println("顾客" + c.getName() + "订票成功");
				System.out.println("一共成功订票" + now.getSum() + "张,航班号为" + FNum );
				return;
			}
		}
		
		booked.add(c);
		free -= c.getSum();
		System.out.println("顾客" + c.getName() + "订票成功");
		System.out.println("一共成功订票" + c.getSum() + "张,航班号为" + FNum );
	}
	
	public void cancel(Customer c)
	{
		Iterator<Customer> it = booked.iterator();
		
		boolean found = false;
		for ( ; it.hasNext(); )
		{
			Customer now = it.next();
			if (now.getName().equals(c.getName()))
			{
				found = true;
				free += c.getSum();
				System.out.println("退票成功");
				if (now.getSum() == c.getSum())//如果顾客将自己买的票全部退票,则从买票列表删除该顾客
				{
					booked.remove(now);
					break;
				}
			}
		}
		if (!found) System.out.println("退票失败,您没有定该航班的机票!");
		System.out.println();
		
		it = waiting.iterator();
		for ( ; it.hasNext(); )
		{
			Customer now = it.next();
			if (now.getfNum().equals(FNum) && now.getSum() <= free)
				book(now);
		}
	}
}

class Menu
{
	private ArrayList<Flight> flights;
	Flight temp;
	
	public void init()
	{
		flights = new ArrayList<Flight>();
		Flight f = new Flight(1, "北京","k2", 20);
		addFlight(f);
		f = new Flight(2, "北京","k3", 23);
		addFlight(f);
		f = new Flight(3, "成都","k4", 25);
		addFlight(f);
	}
	
	public void addFlight(Flight flight) //加入一条航线
	{
		flights.add(flight);
	}
	
	public void query() //查询
	{
		System.out.println("请输入要查询的目的地城市:");
		Scanner in = new Scanner(System.in);
		String d = in.next();
		Flight temp;
		
		Iterator<Flight> it = flights.iterator();
		
		boolean found = false;
		for ( ; it.hasNext(); )
		{
			temp = it.next();
			if (temp.getDestination().equals(d))
			{
				found = true;
				temp.showInfo();
			}
		}				
		if (!found)System.out.println("没有检索到相关信息");	
	}
	
	public void book() //订票
	{
		Scanner in = new Scanner(System.in);
		System.out.println("请输入订票人数:");
		int t = in.nextInt();
		
		Flight temp; // 航班类临时变量
		String tp, tp1; //tp 为航班号,tp1为姓名
		int tem; // temporary
		
		for (int i = 0; i < t; i++)
		{
			System.out.println("请输入航班号,您的姓名,以及您想要订购的票数");
			
			tp = in.next();
			tp1 = in.next();
			tem = in.nextInt();
			
			Customer c = new Customer(tp1, tp, tem); //构造函数参数依次为:姓名、 航线号、 所购票数
			Iterator<Flight> it = flights.iterator();
			
			boolean found = false;
			for ( ; it.hasNext(); )
			{
				temp = it.next();
				if (temp.getFNum().equals(tp))
				{
					temp.isbook(c);
					found = true;
					break;
				}
			}
			
			 if (!found) System.out.println("输入的航线不存在!");
			 System.out.println();
		}
		
	}
	
	public void cancel() //退票
	{
		Scanner in = new Scanner(System.in);
		System.out.println("请输入退票人数:");
		int t = in.nextInt();
		Flight temp; // 航班类临时变量
		String tp, tp1; //tp 为航班号,tp1为姓名
		int tem; // temporary
		
		for (int i = 0; i < t; i++)
		{
			System.out.println("请输入航班号,您的姓名,以及您想要退票的票数");
			tp = in.next();
			tp1 = in.next();
			tem = in.nextInt();
			
			Customer c = new Customer(tp1, tp, tem); //构造函数参数依次为:姓名、 航线号、 所购票数
			Iterator<Flight> it = flights.iterator();

			boolean found = false;
			for ( ; it.hasNext(); )
			{
				temp = it.next();
				if (temp.getFNum().equals(tp)) //确认航班号确实存在
				{
					temp.cancel(c);
					found = true;
					break;
				}
			}
			 if (!found) System.out.println("输入信息有误");
			 System.out.println();
		}		
	}
	
	public void menu() //显示菜单
	{
		System.out.println("----------");
		System.out.println("1.航线查询"); 
		System.out.println("2.办理订票");
		System.out.println("3.办理退票");
		System.out.println("4.退出系统");
		System.out.println("----------");
		
		Scanner in = new Scanner(System.in);
		int order = in.nextInt(); //指令
		
		switch(order)
		{
		case 1: query(); break;
		case 2: book(); break;
		case 3: cancel(); break;
		case 4: System.exit(0); in.close();break;
		default: System.out.println("输入错误,请重新运行订票系统!");
		}
		menu();
	}
}

public class test 
{	
	public static void main(String args[] )
	{
		Menu m = new Menu();
		m.init();
		m.menu();
	}
}

-------------------------------这些是实验心得体会------------------------------

五、心得体会(要详细,编程中碰到的问题及解决方案)

搜过的资料(都是超链接,可直接点击

Java中关于nextInt()、next()和nextLine()的理解

 java获取用户输入的字符串!...

JAVA中几种读取文件为字符串

eclipse中如何去除警告:Class is a raw type. References to generictype Class<T> should be parameterized

解决“List is a raw type. References to generic type List”提示的问题

java泛型问题 关于警告:XXis a raw type【转】

什么是rawType

 java出现Resourceleak: 'XXX' is never closed 解决方案

初始化ArrayList的两种方法

java:String使用equals和==比较的区别

 java.lang.NullPointerException 空指针异常问题

Java_List元素的遍历和删除

 Java LinkedList基本用法

 java中System.exit()方法

Java入门系列:实例讲解ArrayList用法

改进和思考:

1.        在写 Menu类 的 book() 和 cancel() 函数时,发现其实有大量重叠部分,因为 cancel() 函数在删除完以后,也是要遍历该航线的 Waiting列列表,看有没有 Customer 对象能够完成之前没能完成的订票。也就是说,book()函数里已经实现过的功能,还需要在 cancel()函数里在实现一次。

这样导致的结果,就是代码看上去又拖沓又冗长,于是想了个办法,在航班类里加入 book() 和 cancel() 函数,并且将 Customer类对象作为参数传到航班类里,这样就能直接调用 Flight 类的函数来完成订票退票,可以提高代码的复用性。

而且,如果传入 Customer类对象,那么,其实航班类的很多get函数都可以直接去掉了,一下子使代码简洁多了,看起来终于舒服多了,之前的一堆get函数很是拖沓…

从这个优化的过程感受到的就是:

不要急着敲代码,而是先想想能不能有更好的思路,比如这题,刚开始时就没有想到特别透彻清楚明白的程度,导致后来,实现函数的时候才发现,完全不用那么繁琐,明明有更简单的方法来实现,我为什么要弄得那么复杂?

所以,先别急着敲代码,而是应该先把每一个细节琢磨清楚,多问问自己:还能不能再简化一点?能不能再把代码写优美一点?一拿到题目就做,往往是最浪费时间的方法,因为后面用来修改和优化的时间会更多。我应该做的是,每次把所有优化的可能考虑周全,尽量把类里的方法减少到最少,同时提高这些方法的利用率,我觉得这才是实验里最为关键的部分。

2.      着手于简化、简化再简化

将不必要的get 和 set 函数都去掉,例如 Customer类,该题不考虑顾客改名的情况,故而不需要  name 的 set方法;此外,该题没有一个顾客同时买多个航线的飞机票的情况,就算真的要处理这种情况,按照我的代码设计的逻辑,也是要新建一个 Customer 对象的,因为我觉得这样做更方便处理。

  再说详细一些就是,如果aaa同时买了 K2 和 K3 航班的票,那么,我打算采取的,不是将这这个航班的购票数都存在一个 Customer的对象里,而是打算再建立一个 Customer对象,保存 K3 的航班线名臣和K3的订票数。因为在办理订票和退票时,我们都是根据航班号来查航线的。如果把不同的航班号,存在同一个 Customer对象里,其实无形中加大了查找特定某航线的难度。

  所以,照着这么说,航线名也是不会改的,如果这个顾客买的某个航线的票,全都被他自己后来退光了,那也只需要在那个航线的 booked 链表里删掉这个顾客的信息即可

  这么想来,其实 fNum 的 set 方法也可以去掉,因为就本题的考虑,根本用不到这个方法。

  唯一需要保留的 set 方法,是sum的set方法,因为可能存在退票但没有退完的情况,这时就需要改变 Customer对象的订票数了。

  同理,对于 Flight 类,也应进行一次这样的考虑和排查。因为方法是为了解决问题而设计的,不是为了写一个方法而去写一个方法。所以,如果能更简单地解决问题,就不要把问题弄复杂了!~

3.        情况考虑要比题目设置更加周全一些

题目好像没提到一点,其实在进行订票时,也应该进行一轮该航班的 booked 列表的遍历。

因为,考虑真实情况时,同一个顾客是可以多次订票的,所以,我们需要先知道顾客之前有没有订过票,订过和没订过的处理方式是不同的。

4.      语法点和知识不太熟练,导致的失误

4.1. 在进行字符串比较时,又忘了两个字符串之间是不能直接用 == 来判断相等的,而是应该用 equals 函数,又一次把 C++的语法规则套在Java上用了…说明我学的还是不到位啊!

4.2. 此外,用于读取 String对象的 next 和 nextLine,必须弄清楚两者的区别,正确选择用哪个,否则用了 equals 来比较以后,得到的结果仍然是不相等

4.3. 使用泛型前,要先对其进行初始化,否则会出现空指针错误

-------------------------------其他相关文章------------------------------

 [ Java学习 ] 类的其他文章汇总(都是超链接,可直接点击):

[ Java学习 ] 实验 银行业务模拟

[ Java学习 ] 破除思维定势之C++ 和 Java 的差异001

[ Java学习 ] 破除思维定势之C++ 和 Java 的差异002

[ Java学习 ] 破除思维定势之C++ 和 Java 的差异003

[ Java学习 ] 包语句package等语句的汇总整理

[ Java学习 ] Java变量以及内存分配(非常重要)

[ Java学习 ] 其他知识总结(重要)

[ Java学习 ] “goto语句“和 “continue + 标号”的不同待遇

[ Java学习 ] toString方法 和equals方法

 [ Java学习] 正则表达式与模式匹配

[ Java学习 ] 查阅资料整理001

[ Java学习 ] 查阅资料整理002

[ Java学习] 查阅资料整理 003

[ Java学习] 查阅资料整理 004

[ Java学习 ] 一道Java好题的详细题解 001

[ Java学习 ] 一些Java程序 001

[ Java学习 ] 一些Java程序 002

原文地址:https://www.cnblogs.com/mofushaohua/p/7789349.html