201521123037 《Java程序设计》第4周学习总结
1. 本周学习总结
1.1 尝试使用思维导图总结有关继承的知识点。
1.2 使用常规方法总结上课内容。
1、识别类。对于一个系统中,对于名词大多为类或属性,对于动词大多为方法。
2、注释。类注释、方法注释,以/*开头,*/结尾,其中@param 表示传入的参数@return 表示返回的参数
3、继承与多态
* 继承(抽取共同特征,复用代码)
*子类继承父类:子类is a父类(is a关系是继承的一个明显特征),子类继承时将获得父类的属性和方法,并具有自身特有的属性和方法。
*extends 一个子类继承父类时所用的关键字,子类名extends父类名。
*override 父类的方法在子类中被重新定义。
*super 调用父类被子类隐藏的同名属性,调用父类方法(与子类方法名相同,参数相同),调用父类构造函数super()(注:创建子类时父类构造函数都会被调用;super()必须放在子类构造函数的第一行;super()也可以重载)
*final 不变的
*修饰类 该类不可被继承
*修饰方法 该方法不可被覆盖
*修饰对象 该对象的引用不可变,值可变
*修饰变量 该变量值不可变,相当于常量
*abstract 抽象的
*修饰类 该类必须被继承
*修饰方法 该方法必须被覆盖
*抽象方法一定在抽象类中,抽象类可能有非抽象方法
*权限
*private 只限在类内部存取
*无 类内部、同包类可存取,不同包类不可存取
*protected 类内部、同包类可存取,不同包子类可存取
*public 类内部、同包、不同包可存取
*object(是所有类的父类)
*toString方法:未被覆盖时,输出类名和散列码
*equals方法:未被覆盖时,比较的两个对象的引用
*多态(相同的形态,不同的行为)
*子类的引用可赋给父类类型的变量
*instanceof可以判断父类所引用对象实例的实际类型
*cast强制类型转换 可将父类所引用对象强制转换为引用对象类型
2. 书面作业
1. 注释的应用
使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看。(截图)
- 类的注释
- 方法的注释
2. 面向对象设计(大作业1,非常重要)
2.1 将在网上商城购物或者在班级博客进行学习这一过程,描述成一个故事。(不得少于50字)
在当当网上购买图书。打开当当网,可以看到搜索栏、商品分类、购物车。在搜索栏上选择图书类,并输入三毛,点击搜索。出现了关键字有三毛的全部商品,并按综合排序展现在眼前,除了综合排序还有销量、好评、出版日期可供选择排序,可按相应要求进行筛选。全部商品的窗口右边是当当自营,点击进去,页面和全部商品的页面类似。点击《撒哈拉沙漠》,可查看该书的详细信息,将该书加入到购物车,可以看到总价,进行结算。
2.2 通过这个故事我们能发现谁在用这个系统,系统中包含的类及其属性方法,类与类之间的关系。尝试找到这些类与属性,并使用思维导图描述类、属性、方法及类与类之间的关系。
用户在用这个系统。系统中包含的类有所有商品、购物车,方法有搜索。其中所有商品的子类为图书、服饰、运动户外等,父类的属性有商品的名称、价格,子类特有的属性有出版社或产地。购物车中属性是商品,方法是对选中或所有商品进行总计以及商品数量的增减。搜索中调用商品类和其中的当当自营类,子方法有按相应要求进行排序或筛选。
2.3 尝试使用Java代码实现故事中描述的这一过程(不必很完善),将来要在这个基础上逐渐完善、扩展成一个完整的面向对象的系统。(可选:加分)
参考资料:
UML类图
面向对象案例-借款者姓名地址.zip
3. ManagerTest.zip代码分析
分析ManagerTest.zip中的代码,回答几个问题:
3.1 在本例中哪里体现了使用继承实现代码复用?回答时要具体到哪个方法、哪个属性。
super()调用了父类方法。super(n,s,year,month,day)指调用父类的有参构造函数(只能放在子类构造函数的第一行),super.getSalary()调用了父类同名的方法。父类的所有属性都被子类继承,有name、salary、hireDay。
3.2 Employee类及其子类Manager都有getSalary方法,那怎么区分这两个方法呢?
调用getSalary方法关键在于对象是属于哪一类,如果属于父类则调用父类的,如果属于子类则调用子类的,出现子类的引用赋给父类的对象时,子类中若存在该方法,则调用,否则调用父类的。
3.3 文件第26行e.getSalary(),到底是调用Manager类的getSalary方法还是Employee类的getSalary方法。
对于父类的对象调用Employee类的方法,当其中是有子类的引用赋给父类的对象时,调用Manager类的方法。
3.4 Manager类的构造函数使用super调用父类的构造函数实现了代码复用,你觉得这样的有什么好处?为什么不把父类构造函数中的相关代码复制粘贴到Manager的构造函数中,这样看起来不是更直观吗?
在每次对子类进行初始化成员时,都能够对继承下来的属性进行初始化。若有多个子类要对属性初始化时(继承父类的属性以及子类特有的),使用复用父类的构造方法显得简洁明了。
4. Object类
4.1 编写一个Fruit类及属性String name,如没有extends自任何类。使用System.out.println(new Fruit());是调用Fruit的什么方法呢?该方法的代码是从哪来的?尝试分析这些代码实现了什么功能?
调用Fruit的toString方法。该方法是继承父类object,复用其中的toString()方法。输出的内容为类名和散列码,这些代码能够满足一些基本操作,不用在每次需要前进行编写,可直接调用。
4.2 如果为Fruit类添加了toString()方法,那么使用System.out.println(new Fruit());调用了新增的toString方法。那么其父类中的toString方法的代码就没有了吗?如果同时想要复用其父类的toString方法,要怎么操作?(使用代码演示)
父类的toString方法仍然存在。使用关键字super复用父类的方法,即super.toString()。
4.3 Fruit类还继承了Object类的eqauls方法。尝试分析其功能?自己编写一个equals方法覆盖父类的相应方法,功能为当两个Fruit对象name相同时(忽略大小写),那么返回true。(使用代码证明你自己覆盖的eqauls方法是正确的)
Object类的equals方法比较两个对象的引用是否相等。
- 查看Object的源代码
- 覆盖父类的equals方法
4.4 在4.3的基础上使用ArrayList fruitList存储多个fruit,要求如果fruitList中已有的fruit就不再添加,没有的就添加进去。请编写相关测试代码。并分析ArrayList的contatins方法是如何实现其功能的?
package sy3;
import java.util.ArrayList;
import java.util.Scanner;
class Fruit extends Object{
String name;
Fruit(String name){
this.name=name;
}
public boolean equals(Object obj) {
if (obj instanceof Fruit) {
Fruit u = (Fruit) obj;
return this.name.equals(u.name);
}
return super.equals(obj);
}
}
public class Main {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
ArrayList<Fruit> fruitList=new ArrayList<>();
while(true){
String a=in.next();
if(a.equals("end")) break;
Fruit a1=new Fruit(a);
if(!fruitList.contains(a1)){
fruitList.add(new Fruit(a));
}
}
System.out.println(fruitList.size());
for (Fruit e : fruitList) {
System.out.println(e.name);
}
}
}
- 需要注意到的是contains的源代码中调用了o.equals(elementData[i]),在编写代码时,数组存的是对象,equals比较的结果永为false,此时需要在Fruit类中覆盖equals方法。
- contains内容为空,遍历数组查看有没有为空的成员,若有返回1,没有则返回-1;contains内容不为空,遍历数组查看相同的成员(调用Object.equals()),若有返回1,没有则返回-1。
5. 代码阅读:PersonTest.java(abstract、多态)
5.1 画出类的继承关系
5.2 读懂main函数,将自己推测的出代码运行结果与真正运行结果进行比较。尝试分析原因
- 主函数对Person类数组中年龄进行冒泡排序,由小至大排列。并且输出的格式是各个子类覆盖的输出格式。
- 当子类的引用赋给父类的对象时,在编译过程,系统将其看作父类的对象,在运行过程中对该对象进行子类的实例化如果子类有相应的方法就调用子类的方法,没有的话调用父类的方法(动态绑定)。
5.3 子类中里面使用了super构造函数,作用是什么?如果将子类中的super构造函数去掉,行不行?
- 对子类从父类继承的成员进行初始化。看情况而定。去掉的话,会默认在构造子类特有的属性前对继承父类的属性进行无参构造,如果父类未编写无参构造,意味着无法给子类从父类继承的成员赋值,导致错误。
5.4 PersonTest.java中的代码哪里体现了多态?你觉得多态有什么好处?多态和继承有什么关系吗?
- 很明显的,主函数中,子类引用赋给父类类型对象。
- 将不同子类的对象归为一类,进行统一操作。
- 多态与继承密切相关,多态是写一个方法,它只接收父类作为参数,编写的代码只与父类打交道,运行这个方法时,实例化不同的子类对象(new 一个对象)。
参考文件:PersonTest.java
3. 码云代码提交记录
在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
4. PTA实验
题目集:jmu-Java-03-面向对象1-基础-封装继承 中的
函数(4-1, 4-2, 4-3,4-4较难选做)
编程(5-4, 5-5, 5-6)
- 4-1
- 调用同包类的方法时,采用同包的类名.方法名的形式。
- 5-4
- 抽象类必须被继承,计算数组中面积总和和周长总和的方法放在抽象类里面比较合适,因为子类的引用可赋给父类对象,方便计算。
- 对于长度不定的数组需要使用Arraylist初始化对象。
- 控制双精度输出格式需要调用DecimalFormat类。
- 5-5
- 覆盖父类的equals方法时,注意方法名,参数类型、数量必须一致。equals比较的是对象时,比较的是引用;若要比较子类的值,需要先将强制父类转化为子类,并依次对属性进行比较。
- 该题目要求若有相同属性的对象,则不加入数组中,可见该数组为长度不定的数组,需要用Arraylist定义该数组。用for循环让新建的对象与数组中的元素进行一一比较。
- 问题:执行Arrays.toString(PersonOverride.class.getConstructors())输出的是[],而不是其构造函数。
- 解决:构造函数必须为public类,且输出的构造函数顺序,与程序编写顺序有关。