本次 Lab 时长为 2 周,DDL 为 11 月 6 日 23:59。
附件下载(包括问答题和实验报告模板):https://bhpan.buaa.edu.cn/link/AA96D0CA694BB74ABFA070F38B6C527AC6
Object 类Object 类中方法的能力本实验假设你明白:
final的(除非是匿名类的方法的参数)本次实验不会涉及以下内部类的常用技巧:
也不会涉及以下特殊情况:
阅读下面这段代码,回答问题。
1 | class Outer { |
在注释部分填写代码,使程序先后输出 30、20、10。提交包含代码和运行结果的截图。
注意:
阅读下面这段代码,回答问题。
1 | interface Inter { |
在注释部分填写代码,使程序输出 DuluDulu。提交包含代码和运行结果的截图。
注意:
本题与 Lab 6 的一道附加题相同,不要求提交代码或解答,但建议实操或思考其实现。
在前面实验的 Shape 的基础上,定义一个满足如下需求的 IShapeFactory 接口:
Shape makeShape(double a, double b) ,返回一个由 a 和 b 指定大小的 形状;
用单例模式 + 工厂方法模式的思想修改矩形、椭圆、菱形类:
每一个类都增设一个 private static IShapeFactory factory 字段
类中的
factory用于生成该类的形状对象,比如Rectangle类中的factory,其makeShape方法返回Rectangle对象,直接使用匿名类为factory进行静态初始化,不允许像 Extra 2 那样定义工厂类
进行其他的修改,使外界的其他类能够获取到 factory 并成功构造形状对象
选择你认为合适的方式编写测试类:
ShapeFactoriesTest.makeShape 方法。使用匿名类,依然是为每一个形状创建了一个对应的工厂,因此本质上依然是工厂方法模式,区别在于不用显式定义新的类(据说编码过程中,起名字是最麻烦的事情)。
工厂方法模式的应用中,每一种工厂通常只有一个实例,因此它经常和单例模式一起被使用。
这是一个主动要求大家造轮子的题,因此不允许继承或组合任何 Java 自带的容器(除了数组)。
关于内部类实现迭代器,可以参考:An iterator that is an inner class。
在 Shape 的基础上,定义一个满足如下需求的 ShapeSequence 类:
private Shape[] shapesShapeSequence(int size)
size 用于指定 shapes 的最大长度,如果 size 是负数,那么按照 0 来处理。shapes 进行初始化赋值,在其他过程中 shapes 的大小不应该被改变public void add(Shape shape)
shapes 中添加一个新的元素shapes 被填满时,什么都不做public String toString()
[Type, Type,...]Type 是形状类型的全小写英文单词,比如 rectangle、ellipsepublic SequenceIterator iterator() {return new SequenceIterator(); }private class SequenceIterator,它用于序列遍历的迭代器
0public boolean isEnd(),迭代器完成遍历时,返回 true
public Shape current(),返回当前迭代器指向位置的 Shape 对象
isEnd() 是 true 时,访问 current 是非法操作public void moveNext(),使迭代器移动到下一个元素的位置
isEnd() 是 true 时,什么都不做public boolean equals(Object o),当 o 是 SequenceItetator 类型的、且 o 和 this 的外部类对象相同、且 o 和 this 的位置相同时,返回 true对于 ShapeSequence 的 iterator 方法,由于内部类是 private的,如果直接返回 SequenceIterator,是无法编译通过的。因此,你可能需要使用接口来进行实现的隐藏,具体可以参考 An iterator that is an inner class。为此,你可以更改上文给出的需求。
编写测试类并描述你的测试计划。提交项目代码文件夹。
注意:toString 和 equals 是 override 继承自 Object 的方法,尽量避免出现诸如 ToString、 equals 的参数类型不是 Object 等情况。
题目中省略了一些实现上必要但是方式不唯一的属性:比如你可以在 ShapeSequence 类中声明一个 int 属性来表示当前容器被填充到了什么位置;给 SequenceIterator 一个 int 属性表示当前迭代器指向的位置,当使用 isEnd 时,判断迭代器位置和外部类容器的填充位置进行比较。当然,你可以按自己的想法设计。
题外话
- 本题的目的是进行内部类、
Object相关的综合实践。- 后续容器和泛型课程中,会引入可变长容器以及匿名类实现的迭代器。
- 虽然我们上机并不评测程序的性能,但是在实现本题的
toString时,还是推荐考虑使用StringBuilder。- 你可以考虑一下不使用内部类时要如何实现迭代器:内部类为这种数据访问是否带来了足够的便利?(不要求作答)
- 为什么
SequenceIterator被限定为了private?(不要求作答)