20162330 第三周 蓝墨云班课 泛型类-Bag 练习
目录
题目及要求
- 代码运行在命令行中,路径要体现学号信息,IDEA中,伪代码要体现个人学号信息;
- 参见Bag的UML图,用Java继承BagInterface实现泛型类Bag,并对方法进行单元测试(JUnit),测试要涵盖正常、异常情况、边界情况;
- 课上提交测试代码和测试运行的结果截图,截图要求全屏截图,包含自己的学号信息,否则无效;测试Bag类的代码中至少包含一个自定义类如Student;
- 课下完成码云上代码的上传。
- 【附】Bag的UML图:
思路分析
- 首先自定义一个Bag类,使用
public class Bag<T> implements BagInterface<T>
实现给出接口的所有方法框架,之后在里面通过泛型类型 T 自定义一个数组,通过填充方法来完善Bag类。考虑到给出的接口含有add
、remove
、isEmpty
等方法,如果使用 List 创建对象实现有些简单,所以我选择了使用 Object 类定义数组实现这些方法。
在 Bag 类的 UML类图 中,我们可以清楚地知道每个方法的返回类型、参数及需要实现的功能,大部分功能的实现比较框架化,比如:getCurrentSize()
、isEmpty
、add(T newEntry)
、remove()
等,其方法填充内容基本符合以下框架:
public <返回类型> <函数名>(<参数>){
//初始化返回值参数对象
//循环(遍历、修改元素)
//条件(何时修改、赋值)
//返回值(参数)
}
之所以能用 循环 + 条件 的框架是因为这些方法基本都涉及遍历环节,我也使用了几种不同的遍历方式。
需要注意的是最后一个方法 toArray()
,这个方法相对陌生,我查找了API,关键句如下:
按 适当顺序 返回包含此列表中所有元素的数组;
如果指定的数组能容纳队列,并有剩余的空间,那么会将数组中紧接 collection 尾部的元素设置为 null。
- 所谓的“适当顺序”,可以理解为不同与原来数组排列元素的顺序,我又继续看了UML类图中的这一方法的注释:
A new array of entries currently in the bag.
- 我的思路是将原来数组中的空值元素都填补为同一类型的相同的值,然后再重新返回这个数组,这样就可以通过一个含空值的数组调用此方法之后的元素容量进行单元测试。实现代码如下:
/*
Shows all objects in a new array of food bag entries.
*/
public T[] toArray() {
int j = food.length - 1;
for (int i = 0;i<food.length;i++) {
food[j] = "apple";
if (food[i] == null) { //将空值全部填补
food[i] = food[j];
j--;
}
}
return (T[]) food;
}
遇到的问题和解决过程
【问题】在使用Junit测试
add(T newEntry)
方法时,Junit测试异常:
【解决方法】我仔细看了一下自己写的 add 方法:
public boolean add(T newEntry) {
boolean boo = false;
for (Object i : food) {
if (i == null) {
i = newEntry; //添加到第一个空值位置
boo = true;
break;
}
}
return boo;
}
由于使用foreach遍历比较简单,我就没有考虑其他问题。IDEA的提示,给 i 重新赋值的那条语句中的 i 是多余的:

我就想不通为什么是多余的,于是又开始检查 foreach 的结构框架:
for(<元素类型> <元素变量> : <遍历对象>){
引用元素变量的相关语句;
}
修改了几次数组类型之后还是不对,于是我认为是foreach方法出现问题,就做了一个foreach的测试类,发现果然是foreach方法的问题,同样的修改赋值语句,使用for循环遍历就正常,使用foreach就不能进行相应赋值:

接着,我开始使用debug单步调试:(单击图片可放大)
[](http://images2017.cnblogs.com/blog/1062725/201710/1062725-20171007185542708-250193647.png)
刚开始设断点,我并没有注意观察细节,只是跟着步骤走了一遍,又跟踪了一遍才发现给 i 赋值的语句好像并没有效果,这一句出现了问题。我又仔细地跟踪了一遍,发现add元素的地址和原来空值的地址不一样,而最后数组添加的是空值的地址:
[](http://images2017.cnblogs.com/blog/1062725/201710/1062725-20171007185832974-1747717902.png)
[](http://images2017.cnblogs.com/blog/1062725/201710/1062725-20171007185845349-1292468436.png)
所以总结起来就是,i 原来对应的地址就不是指向数组元素的,所以只要用其他循环(for循环)替代即可正常修改原数组的元素:

如果一定要使用foreach修改数组元素的话,那只能再另外加一层循环:
public boolean add(T newEntry) {
boolean boo = false;
for (Object i : food) {
if (i == null) { //foreach不能修改数组元素
for (int j = 0; j < food.length; j++) { //重新使用for循环赋值
if (food[j] == i) {
food[j] = newEntry; //添加到第一个空值位置
break;
}
}
boo = true;
break;
}
}
return boo;
}
至于我的验证是否正确,我又查找了相关资料,一种说法是:
foreach结构中的元素变量是个基本数据类型,在遍历时不指向数组元素的地址,它只代表数字它自己。
- 还有一个实例可以更好地证明我的验证:
for (Integer temp : list)
{
if (temp == 1)
{
temp = temp * 2;
}
}
根据oracle的官方文档,正式翻译应该如下:
for (Iterator i = list.iterator(); i.hasNext(); )
{
float i0 = (Integer)i.next();
if(i0 == 1)
i0 = i0*2;
}
所以foreach中的 temp变量只是一个局部变量(i0),而且还是集合中元素的一个副本,并不是元素本身。这样才导致输出“修改过的数组”时,仍然输出原数组。
综上所述,我的验证正确,foreach只适合遍历数组,在实现涉及到修改数组元素的功能时,不宜使用,会造成赋值失败。
代码实现及托管链接
这里只贴出Bag类代码和运行成功截图,其余代码见相关代码托管链接:
【BagInterface类】
【Bag类】
【BagTest类】Bag类如下:
/**
* A finite number of objects,not necessarily distinct,in no particular order,
* and having the same data type(collection).
*
* @author 20162330
*/
public class Bag<T> implements BagInterface<T> {
private Object food[] = new Object[5];
/*
Returns the current number of objects in the bag(except null).
*/
public int getCurrentSize() {
int foodSize = 0;
for (Object i : food) { //foreach遍历
if (i != null)
foodSize++;
}
return foodSize;
}
/*
Demonstrates if the food bag is empty(null).
*/
public boolean isEmpty() {
boolean boo = true; //默认为空
for (Object i : food) {
if (i != null) {
boo = false;
break;
}
}
return boo;
}
/*
Adds a given object to the food bag,according to whether the addition succeeds,
return true or false.
*/
public boolean add(T newEntry) {
boolean boo = false;
for (Object i : food) {
if (i == null) { //foreach不能修改数组元素
for (int j = 0; j < food.length; j++) { //重新使用for循环赋值
if (food[j] == i) {
food[j] = newEntry; //添加到第一个空值位置
break;
}
}
boo = true;
break;
}
}
return boo;
}
/*
Removes an unspecified object from the food bag,if possible.
*/
public T remove() {
Object n = null;
for (int i = 0; i < food.length; i++) {
if (food[i] != null) {
n = food[i];
food[i] = null; //移除第一个不为空的元素
break;
}
}
return (T) n;
}
/*
Removes an occurrence of a particular object from the food bag,if possible.
*/
public boolean remove(T anEntry) {
boolean boo = false;
int i = 0;
while (i < food.length) {
if (food[i] == anEntry) {
food[i] = null;
boo = true;
break;
}
i++;
}
return boo;
}
/*
Removes all objects from the food bag.
*/
public void clear() {
int i = 0;
do { //do-while方式遍历
food[i] = null;
i++;
}
while (i < food.length);
}
/*
Counts the number of times an object occurs in the food bag.
*/
public int getFrequencyOf(T anEntry) {
int t = 0;
for (Object i : food) {
if (i == anEntry)
t++;
}
return t;
}
/*
Tests whether the food bag contains a particular object.
*/
public boolean contains(T anEntry) {
boolean boo = false;
for (Object i : food) {
if (i == anEntry) {
boo = true;
break;
}
}
return boo;
}
/*
Shows all objects in a new array of food bag entries.
*/
public T[] toArray() {
int j = food.length - 1;
for (int i = 0;i<food.length;i++) {
food[j] = "apple";
if (food[i] == null) { //将空值全部填补
food[i] = food[j];
j--;
}
}
return (T[]) food;
}
}
Junit单元测试截图:(单击图片可放大)
[](http://images2017.cnblogs.com/blog/1062725/201710/1062725-20171007193120865-790803238.png)
感想
- 这次实践中解决问题确实花费了不少时间,不过我一直坚持独立思考,最终顺利解决问题,同时又练习了一下几种不同的循环(遍历)方式,Junit测试与之前相比也更全面了,也算是又体验了一回“做中学”。
参考资料
20162330 第三周 蓝墨云班课 泛型类-Bag 练习的更多相关文章
- 20162330 第十二周 蓝墨云班课 hash
题目要求 利用除留余数法为下列关键字集合的存储设计hash函数,并画出分别用开放寻址法和拉链法解决冲突得到的空间存储状态(散列因子取0.75) 关键字集合:85,75,57,60,65,(你的8位学号 ...
- 疫情下的在线上课方案:QQ直播+蓝墨云班课
目录 疫情下的在线上课方案:QQ群视频(腾讯课堂)+蓝墨云班课 使用QQ进行直播 材料 QQ直播步骤 其他问题 使用蓝墨云班课加强学习效果 教材问题 我的直播-小学生硬笔书法基础 我的直播 - C程序 ...
- 补交20145226蓝墨云班课 -- MyCP
蓝墨云班课 -- MyCP.java 具体描述: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt ...
- 补交20145226蓝墨云班课 -- MyOD
蓝墨云班课 -- MyOD.java 具体描述: 编写MyOD.java 用java MyOD XXX实现Linux下od -tx -tc XXX的功能. 提交测试代码和运行结果截图,加上学号水印,提 ...
- 补交20145226蓝墨云班课 -- Arrays和String单元测试
蓝墨云班课 -- Arrays和String单元测试 具体描述: 在IDEA中以TDD的方式对String类和Arrays类进行学习 测试相关方法的正常,错误和边界情况 String类 charAt ...
- 补交 20155202 蓝墨云班课 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能
蓝墨云班课 编写MyCP.java 要求: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX ...
- MyCP.java蓝墨云班课
题目要求: 编写MyCP.java 实现类似Linux下cp XXX1 XXX2的功能,要求MyCP支持两个参数: java MyCP -tx XXX1.txt XXX2.bin 用来把文本文件(内容 ...
- 20172310 蓝墨云ASL测试 2018-1938872
20172310 蓝墨云ASL测试 2018-1938872 题目: 已知线性表具有元素{5,13,19,21,37,56,64,75,80,88,92},如果使用折半查找法,ASL是多少? 解答:( ...
- 20165223 week3蓝墨云测试总结
1. 表达式0xaa | 0x55的值为 答案: 解析: 0xaa用二进制表示为10101010,0x55用二进制表示为01010101,按位或后为11111111,十进制表示为255,十六进制表示为 ...
随机推荐
- android小程序之幸运菜谱
android小程序之幸运菜谱 前言:刚刚结束短短5天的android公开课程,收获不少,写下来记录一下吧!(因为学校校企公开课的缘故才偶然接触的android,所以只学了这几天,不喜勿喷) 一开始得 ...
- C#隐式转换和显示转换举例--C#基础
高精度的数据类型转换为低精度的数据类型是显示转换,低精度的转换为高精度的是隐式转换. 温馨提示:不能说强制类型转换是从低精度到高精度. int a=666;float b=(float)a: 由a到b ...
- webpacke踩坑-新手
1.题叶-webpack入门指南 2.webpack入门系列 3.w3ctech的webpack入门及实践 4.Express结合Webpack的全栈自动刷新 5.webpack 单页面应用实战 6. ...
- LCT总结(LCT,Splay)
概念.性质简述 LCT(Link-Cut Tree),就是动态树的一种,用来维护一片森林的信息,滋磁的操作可多啦! 动态连边.删边 合并两棵树.分离一棵树(跟上面不是一毛一样吗) 动态维护连通性 维护 ...
- SPOJ:To the moon
题面 vjudge Sol 主席树模板 # include <bits/stdc++.h> # define RG register # define IL inline # define ...
- Poj3678:Katu Puzzle
大概题意 有\(n\)个数,可以为\(0/1\),给\(m\)个条件,表示某两个数经过\(or, and, xor\)后的数是多少 判断是否有解 Sol \(2-SAT\)判定 建图 # includ ...
- js文本框字符数输入限制
我们常常在前台页面做一些文本输入长度的验证,为什么呢?因为数据库字段设置了大小,如果不限制输入长度,那么写入库时就会引发字符串截断异常.今天就给大家分享一个jquery插件来解决这一问题. (func ...
- Could not get dialect instance.
一般此错误都是和数据库有关,请确认数据库配置文件是否配置正确,或者确认数据库是否连接正常
- 设计模式——简单工厂模式(C++实现)
#include <iostream> #include <string> using namespace std; class COperator { public: ; p ...
- CSS Grid 网格布局全解析
介绍 CSS Grid(网格) 布局使我们能够比以往任何时候都可以更灵活构建和控制自定义网格. Grid(网格) 布局使我们能够将网页分成具有简单属性的行和列.它还能使我们在不改变任何HTML的情况下 ...