20175211 2018-2019-2 《Java程序设计》第四周学习总结
教材学习内容总结
第五章 子类与继承
5.1 子类与父类
- 继承是一种由已有的类创建新的类的机制。利用继承,可以先定义一个共有属性的一般类,根据该一般类再定义具有特殊属性的子类,子类继承一般类的属性和行为,并根据需要增加自己的属性和行为。
- 子类通过extends关键字来定义
- 所有类都是Object类的子类
所以所有类都继承了Object类的方法
5.2 子类的继承性
5.3 子类与对象
-
用子类的构造方法创建一个子类对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将子类继承的那部分成员变量作为分配给子类对象的变量。
-
instanceof运算符的左操作元是对象,右操作元是类,当左边的操作元是右边的类或其子类所创建的对象时,instanceof运算的结果是true,否则是false。
5.4 成员变量的隐藏和方法重写
-
当子类声明的成员变量的名字和从父类继承来的成员变量名字相同(声明的类型可以不同),子类会隐藏所继承的成员变量。此时可以使用super关键字调用被隐藏的父类成员变量
-
方法重写是指子类中定义一个方法,这个方法的类型和父类的方法的类型或父类方法的类型的子类型一致,并且这个方法的名字、参数个数、参数的类型和父类的方法完全相同。
-
注意:方法重载不比较方法类型,所以子类里不可以出现仅和父类方法类型不一样,而名称、参数都完全相同的方法,这既不是重写也不是重载。
-
重写父类方法时,不允许降低方法的访问权限,但可以提高访问权限(访问权限从高到低为public、protected、no modifier、private)
5.5 super关键字
- 与this有相似之处
5.6 final关键字
- final关键字可以修饰类、成员变量和方法中的局部变量
- final类不可以被继承,final方法不可以被重写,final声明的变量是常量,声明时没有默认值。
5.7对象的上转型对象
- 上转型对象就是父类引用指向子类对象,例如
Animal a = new Tiger();
5.8 继承与多态
多态性就是指父类的某个方法被其子类重写时,可以各自产生自己的功能行为
5.9 abstract类和abstract方法
- 对于abstract方法,只允许声明,不允许实现,且不允许使用final、static和abstract同时修饰一个方法或类
- abstract类中可以有abstract方法(非abstract类中不可以有abstract方法),也可以有非abstract方法
- abstract类不能用new运算符创建对象
- abstract类的非abstract子类必须重写父类的abstract方法
5.10 面向抽象编程
- 理解abstract类
- 抽象类用抽象方法来封装子类必须要有的行为标准
- 抽象类声明的对象可以成为其子类的对象的上转型对象,调用子类重写的方法,即体现子类根据抽象类里的行为标准给出的具体行为。
- 所谓面向抽象编程,是指当设计某种重要的类时,不让该类面向具体的类,而是面向抽象类,即所设计类中的重要数据是抽象类声明的对象,而不是具体类声明的对象。
- 面向抽象编程的目的是为了应对用户需求的变化,将某个类中经常因需求变化而需要改动的代码从该类中分离出去。面向抽象编程的核心是让类中每种可能的变化对应地交给抽象类的一个子类去负责,从而让该类的设计者不必去关心具体实现,避免所设计的类依赖于具体的实现。
5.11 开-闭原则
- 设计系统时,首先考虑到用户需求的变化,将对应用户变化的部分设计为对扩展开放
- 设计的核心部分是经过经过精心考虑之后确定下来的基本结构,这部分应当是对修改关闭的
教材学习中的问题和解决过程
- 问题1:上转型对象是什么?有什么用吗?
- 问题1解决方案:简单来说,向上转型就是
父类引用指向子类对象
好处在于
这里以父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。不然的话,
如果dosleep以子类对象为参数,则有多少个子类就需要写多少个函数。这也体现了JAVA的抽象编程思想。
其实书上P128页上Example5_11就有体现,同样的animal.cry()可以根据具体的上转型对象做出不同的行为,狗就是“汪汪”,猫就是“喵喵”,那么在其他函数的接口就可以直接使用animal作为参数,而不需要重载方法。比如P130页Example5_12中Boy类的setGirlfriend方法。其实看完面向抽象编程和相应的例子以后就很好理解了。
参考链接JAVA中上转型对象的详细解释,
在java 中,什么叫向上转型
代码调试中的问题和解决过程
- 问题1:构建了一个斐波那契数列类,但是在接收到负数参数时,无法很好的反馈异常,本来想在存入数据时判断calcNextFib()结果是否为-1来处理负数输入,但还是抛出异常。
import java.util.Arrays;
public class Fibonacci {
int length;
int[] fib;
Fibonacci(int n) {
this.length = n;
fib = new int[length];
System.out.println("Please Input a positive number");
if(calcNextFib(n)<0){
for (int i = 0; i < n; i++) {
fib[i] = calcNextFib(i);
}
} else {
System.out.println("Invalid Input");
}
}
private int calcNextFib(int n) {
if (n == 0 || n == 1) {
return 1;
} else if (n > 1) {
return fib[n - 1] + fib[n - 2];
} else {
return -1;
}
}
void printFib() {
System.out.println(Arrays.toString(fib));
}
}
- 问题1解决方案:查看文档,搜索抛出的异常
原来是数组定义的时候长度不能为负数,所以在给数组赋值的时候检查并没有什么用。而我用这种方式来构造斐波那契数列,正好可以用数组长度来检测输入数据的合法性,所以我想到可以直接catch这个异常,修改代码如下
···
Fibonacci(int n) {
this.length = n;
try {
fib = new int[length];
} catch (NegativeArraySizeException e) {
System.out.println("Please Input a positive number");
}
for (int i = 0; i < n; i++) {
fib[i] = calcNextFib(i);
}
}
···
之后我又测试了长度为0时,是可以的,结果创建了一个空数组,测试结果如下
代码托管
上周考试错题总结
- 错题1:下列关于实例方法和类方法的叙述,正确的是
A .类方法不可以操作实例变量,因为在类创建对象之前,实例成员变量还没有分配内存。
B .当创建第一个对象时,类中的实例方法就分配了入口地址,当再创建对象时,不再分配入口地址。
C .实例方法不能通过类名调用,只能由对象来调用。
D .不必创建对象就可以用类名直接调用static方法。
正确答案: A B C D 你的答案: A C D
错误原因:书上有这句原话。。。没印象了。其实很好理解,因为同一个类创建的对象方法是一样的,所以只需要一个方法入口就可以了,需要的时候直接传参进去,不需要存放多个一样的方法。
其他(感悟、思考等,可选)
面向抽象编程的思想很重要!也很好用!能从书上的例子上直接感受到这种思想带来的便利和清晰的架构,看来要多实践实践熟悉这种思想。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 32/32 | 3/3 | 20/20 | 掌握JDB用法 |
第二周 | 261/293 | 3/6 | 18/38 | 无 |
第三周 | 770/1063 | 2/8 | 10/48 | 类 |
第四周 | 555/1508 | 2/10 | 14/62 | 子类与继承 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)