CS61B 课程笔记(DISC 04 Inheritance)
CS61B 课程笔记(DISC 04 Inheritance)
主要的Java概念:
- 继承:
- 子类(
Salmon
)继承自父类(Fish
)。 - 使用
super()
调用父类构造函数,允许子类重用父类的构造逻辑。
- 子类(
- 静态类型 vs 动态类型:
- 静态类型是编译时定义的类型(例如:
Fish fish2 = new Salmon();
)。 - 动态类型是在运行时决定的类型(例如:
fish2
在运行时实际指向Salmon
对象)。
- 静态类型是编译时定义的类型(例如:
- 方法重写 vs 方法重载:
- 方法重写:子类方法与父类方法签名相同,会覆盖继承的版本。
- 方法重载:方法的名称相同但参数不同。
- 动态方法选择:
- 在编译时,根据静态类型来确定方法调用,但在运行时,会根据动态类型来选择合适的方法。
- 类型转换:
- 向下转换允许将父类引用转换为子类类型(例如,将
Fish
类型转换为Salmon
)。 - 如果转换的对象与预期类型不符,可能会抛出转换错误(例如:
ClassCastException
)。
- 向下转换允许将父类引用转换为子类类型(例如,将
- 接口:
- 接口声明方法而不提供具体实现。实现该接口的类必须提供具体的实现。
- 示例:
Plant
接口由Rose
实现。
代码示例:
Fish 和 Salmon 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class Fish {
int weight;
public Fish(int w) { weight = w; }
public void swim() { System.out.println("splash"); }
}
public class Salmon extends Fish {
String home;
public Salmon(int w, String h) {
super(w); // 调用Fish构造函数
home = h;
}
public void migrate() { System.out.println("Migrating to " + home); }
}动态方法选择:
1
2
3
4
5
6
7Fish fish = new Fish();
Salmon salmon = new Salmon();
Fish bob = new Salmon();
fish.swim(); // 调用Fish的swim方法
salmon.swim(); // 调用Salmon中重写的swim方法
bob.swim(); // 由于动态类型为Salmon,调用Salmon的swim方法类型转换:
1
2
3
4
5Fish blueFish = new Salmon();
((Salmon) blueFish).swim(5); // 在将blueFish转换为Salmon后可以运行
Fish redFish = new Fish();
((Salmon) redFish).swim(5); // 运行时错误:ClassCastException
继承中的练习:
理解方法行为在不同的继承层次结构中的表现。例如,
A b0 = new B();
在运行时使用B
类的方法(根据动态类型),但编译时使用静态类型规则。错误级联:如果对象的初始化由于类型不匹配而失败,后续的方法调用也会失败。
以下是关于继承和Java类的中文笔记,整理自您提供的内容:
CS 61B 继承练习
1. 创建猫类
1.1 猫类定义
根据Animal
类定义Cat
类,使得当调用greet()
方法时,打印出“Cat”(而不是“Animal”)。假设如果猫的年龄大于或等于5岁,发出“Meow!”的声音;如果小于5岁,则发出“MEOW!”的声音。
1 | public class Animal { |
2. 猫和狗的测试
2.1 输出分析
假设Animal
和Cat
已按上面的定义,Java在以下行中将打印什么?
1 | public class TestAnimals { |
考虑下列代码的添加:
1 | a = new Dog("Spot", 10); |
这段代码会产生编译错误,原因在于d
的静态类型是Dog
,而a
的静态类型是Animal
。解决此错误的方法是强制转换:
1 | d = (Dog) a; |
详细解释:
这段代码会产生编译错误的原因是因为静态类型不匹配。
在以下代码中:
1
2
3
4 Animal a = new Dog("Spot", 10);
Dog d = new Dog("Fido", 4);
a = new Dog("Spot", 10); // a的类型是Animal
d = a; // 编译错误
a
的静态类型是Animal
,虽然它的动态类型是Dog
,但在赋值给d
时,编译器只检查静态类型。d
的静态类型是Dog
,而a
的静态类型是Animal
,这意味着你不能将一个Animal
类型的引用直接赋值给Dog
类型的变量。如何修复这个错误?
可以使用强制类型转换来修复这个错误:
1 d = (Dog) a; // 强制转换为Dog类型在这种情况下,如果
a
确实是Dog
的实例,转换将成功;如果不是,则会抛出ClassCastException
。
3. 继承中的练习
3.1 查找编译时和运行时错误
交叉删除导致编译时错误或级联错误的行,并在运行时错误的行上画个X。注意,错误可能在类A
、B
、C
中。
1 | class A { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Totoroの旅!
评论