Java继承与多态:释放对象的强大力量
立即解锁
发布时间: 2025-08-18 01:24:34 阅读量: 1 订阅数: 7 

### Java 继承与多态:释放对象的强大力量
#### 1. 继承中的 IS - A 测试
IS - A 测试在继承树的任何位置都适用。如果继承树设计良好,当询问任何子类是否属于其某个超类型时,IS - A 测试应该是合理的。例如,如果类 B 继承自类 A,那么类 B 就是类 A 的一种,即 “B IS - A A”。这种关系在继承树中普遍成立,如果类 C 继承自类 B,那么类 C 对于 B 和 A 都通过 IS - A 测试。
以下是一个动物继承树的示例:
```plaintext
size
picture
food
prey
Wolf
Canine
roam()
makeNoise()
eat()
Animal
makeNoise()
eat()
sleep()
roam()
Canine extends Animal
Wolf extends Canine
Wolf extends Animal
Canine IS - A Animal
Wolf IS - A Canine
Wolf IS - A Animal
```
在这个继承树中,我们可以始终说 “Wolf extends Animal” 或 “Wolf IS - A Animal”,无论 Animal 是 Wolf 的直接超类还是超类的超类。只要 Animal 在 Wolf 的继承层次结构中处于上方,“Wolf IS - A Animal” 就始终为真。这意味着 Wolf 可以执行 Canine 和 Animal 能做的任何事情,即使 Wolf 重写了 Animal 或 Canine 中的某些方法。
我们可以通过 IS - A 测试来验证以下关系是否合理:
|关系|是否合理|
| ---- | ---- |
|Oven extends Kitchen|否|
|Guitar extends Instrument|是|
|Person extends Employee|否|
|Ferrari extends Engine|否|
|FriedEgg extends Food|是|
|Beagle extends Pet|是|
|Container extends Jar|否|
|Metal extends Titanium|否|
|GratefulDead extends Band|是|
|Blonde extends Smart|否|
|Beverage extends Martini|否|
继承的 IS - A 关系是单向的。例如,“Triangle IS - A Shape” 是合理的,所以 Triangle 可以继承自 Shape;但 “Shape IS - A Triangle” 不合理,所以 Shape 不应该继承自 Triangle。
#### 2. 访问级别与继承
访问级别控制着谁能看到什么,对于设计良好、健壮的 Java 代码至关重要。这里主要关注 public 和 private 访问级别,规则如下:
- 子类继承成员时,就好像子类自己定义了这些成员一样。例如,在 Shape 示例中,Square 继承了 rotate() 和 playSound() 方法,对于外部代码来说,Square 类就拥有这两个方法。
- 类的成员包括类中定义的变量和方法,以及从超类继承的任何内容。
- public 成员可以被继承,private 成员不能被继承。
Java 中有四种访问级别,从最严格到最宽松依次为:
```plaintext
private default protected public
```
#### 3. 关于继承的常见问题解答
- **超类能否使用子类版本的方法**:超类不一定知道它的任何子类。即使超类的创建者知道并想使用子类版本的方法,也不存在反向继承。就像孩子从父母那里继承,而不是相反。
- **在子类中如何同时使用超类版本和子类重写版本的方法**:可以使用 `super` 关键字。例如:
```java
public void roam() {
super.roam();
// my own roam stuff
}
```
这段代码先调用继承的 `roam()` 方法,然后执行子类特定的代码。
#### 4. 继承的规则和注意事项
以下是一些关于继承的规则和建议:
- 子类继承超类的所有 public 实例变量和方法,但不继承 private 实例变量和方法。
- 继承的方法可以被重写,但实例变量不能被重写(虽然可以在子类中重新定义,但这不是一回事,而且几乎没有必要这样做)。
- 使用 IS - A 测试来验证继承层次结构的有效性。如果 “X extends Y”,那么 “X IS - A Y” 必须合理。
- IS - A 关系是单向的。例如,“A Hippo is an Animal” 为真,但 “All Animals are Hippos” 为假。
- 当子类重写方法并在子类实例上调用该方法时,将调用重写版本的方法。
- 如果类 B 继承自 A,类 C 继承自 B,那么 “B IS - A A”,“C IS - A B”,并且 “C IS - A A”。
在设计继承时,我们应该:
- 当一个类是超类的更具体类型时使用继承。例如,“Willow extends Tree” 是合理的,因为 Willow 是 Tree 的更具体类型。
- 当有行为(已实现的代码)需要在同一通用类型的多个类之间共享时考虑使用继承。例如,Square、Circle 和 Triangle 都需要旋转和播放声音,将这些功能放在超类 Shape 中可能是合理的,这样便于维护和扩展。
但我们不应该仅仅为了重用另一个类的代码而使用继承,如果超类和子类之间的关系违反了上述两条规则。例如,让 Piano 继承自 Alarm 以获取打印代码是不合理的,因为 Piano 不是 Alarm 的更具体类型。同时,子类和超类必须通过 IS - A 测试。
#### 5. 继承的好处
继承带来了以下好处:
- **避免重复代码**:将公共代码放在一个地方,让子类从超类继承这些代码。当需要更改该行为时,只需在一个地方进行修改,所有子类都会看到更改。
- **定义一组类的公共协议**:通过在超类中定义方法,这些方法可以被子类继承,就向其他代码宣布了一种协议,即 “所有我的子类型(即子类)都可以使用这些方法做这些事情”。例如,Animal 类为所有 Animal 子类型建立了一个公共协议:
```plaintext
Animal
makeNoise()
eat()
sleep()
roam()
```
这告诉世界,任何 Animal 都可以执行这四个操作,包括方法的参数和返回类型。
#### 6. 多态的工作原理
在了解多态之前,我们先看看通常声明引用和创建对象的方式:
```java
Dog myDog = new Dog();
```
这个语句包含三个步骤:
1. **声明引用变量**:告诉 JVM 为引用变量分配空间,该引用变量的类型永远是 Dog,就像一个只能控制 Dog 对象的遥控器。
2. **创建对象**:告诉 JVM 在可垃圾回收的堆上为新的 Dog 对象分配空间。
3. **将对象和引用关联起来**:将新创建的 Dog 对象赋值给引用变量 myDog,就像为遥控器编程一样。
在这种情况下,引用类型和对象类型是相同的,都是 Dog。但在多态中,引用和对象可以是不同的。例如:
```java
Animal myDog = new Dog();
```
这里引用变量类型声明为 Animal,但对象是新创建的 Dog 对象。
#### 7. 多态的实际应用
多态允许引用类型是实际对象类型的超类。以下是一个多态数组的示例:
```java
Animal[] animals = new Animal[5];
animals [0] = new Dog();
animals [1] = new Cat();
animals [2] = new Wolf();
animals [3] = new Hippo();
animals [4] = new Lion();
for (int i = 0; i < animals.length; i++) {
animals[i].eat();
animals[i].roam();
}
```
在这个示例中,我们声明了一个 Animal 类型的数组,然后可以将任何 Animal 的子类对象放入该数组中。通过遍历数组并调用 Animal 类的方法,每个对象都会执行正确的操作。
多态还可以用于方法的参数和返回类型。例如:
```java
c
```
0
0
复制全文
相关推荐










