【JAVA】一文弄清什么是`继承`,`多态`,`向上转型`,`向下转型`
【JAVA】一文弄清什么是`继承`,`多态`,`向上转型`,`向下转型`
Sarzn对于刚刚学习 java
的小白来说,初次面对对象的时候难免会觉得有些不知所措。在这篇文章中我将写下我自己对于继承,多态,向上转型,向下转型的一些理解
希望我的文章对你更深刻的理解 java 的这些概念能有帮助
继承
在生活中我们会说继承家产,继承的意思就是孩子能拥有父母的遗产
在面对对象语言中也有两个概念父类,子类.分别就是父亲和孩子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Animal { // 父类 Animal
public void eat() {
System.out.println("Animal eat something");
}
}
class Dog extends Animal { // 子类 Dog
}
public class Main {
public static void main(String[] args) {
Dog a = new Dog();
a.eat(); // 直接输出Animal eat something
}
}Dog
是子类(孩子), Animal是父类(父亲) 在 java 中我们把这个
是一种 的概念使用 extends关键字来表示
因为Dog(子类)继承Animal(父类),所以Dog 也就有了 Animal 的方法,创建了一个新的Dog(子类)的时候,就能直接调用父类的方法了.
- 如果没有继承,
a.eat()会报编译错误,因为 Dog 没有这个方法 - 但是 Dog 是 Animal 的子类,有
extends继承,Dog 自动拥有 Animal 的方法,a.eat()有输出 这个就是继承.
多态
还是这个例子 但是这次我们要使用多态了
- Dog 和 Cat 都有自己的方法,我们看看会发生什么 我们发现 a,b 这两个对象都用相同的引用 Animal,但是他们调用 eat 方法的时候表现却不同 输出变成了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26class Animal { // 父类 Animal
public void eat() {
System.out.println("Animal eat something");
}
}
class Dog extends Animal { // 子类 Dog
public void eat() {
System.out.println("Dog eat something");
}
}
class Cat extends Animal { // 子类 Cat
public void eat() {
System.out.println("Cat eat something");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog(); // <- 注意这里改变了
Animal b = new Cat();
a.eat(); // 输出 Dog eat something
b.eat(); // 输出 Cat eat something
}
}Dog eat something和Cat eat something这就是多态 多态 就是同一引用的多种表现状态
首先说明Animal a = new Dog();这一句是什么意思,为什么 a
这个对象的类型是 Animal 却用 Dog() 来创建? - 实际创建的是 Dog
对象(决定了实际行为),但用 Animal
类型的引用来操作它(决定了能调用哪些方法)
详见[[【JAVA】Animal a = new Dog();到底是什么意思]]
为什么会产生多态? a 的类型是 Animal,但调用 eat() 时,JVM 在运行时发现 a 实际指向的是 Dog 对象,于是执行 Dog 的 eat(),输出Dog eat something 详见[[【JAVA】动态绑定与静态绑定|【JAVA】动态绑定与静态绑定]]
引申: @Override 重写 重写是指:子类重新定义父类已经有的方法,方法名、参数、返回类型都要一样,但方法体(里面的代码)不一样
1 | class Animal { |
说明
- 重写的前提是继承。没有继承关系,就没有重写。
- 方法签名(方法名 + 参数列表)必须一致,否则就变成”重载”了(这是另一个概念) >重写是多态的基础,多态是重写的效果
向上转型(Upcasting)
把子类对象赋值给父类引用,就是向上转型
如下继承关系
1 | class Animal { |
1 | Animal a = new Dog(); // 向上转型,自动完成,不需要强制 |
几个要点:
- 安全的,自动进行。因为狗”本来就是”动物,所以把它当动物看待没有任何风险
- 看得见的方法变少了。a 的类型是 Animal,编译器只允许你调用 Animal 类里有的方法。bark() 是 Dog 独有的,所以调不到。
- 但实际执行的还是子类的方法。a.eat() 调用的是 Dog 的 eat(),这就是多态
几种方式: 1. 直接赋值 1
Animal a = new Dog();
1
2
3
4
5
6public void fun1(Animal a) {
}
Dog a = new Dog();
fun1(a);1
2
3
4
5public Animal fun2() {
Dog a = new Dog();
return a;
}
Animal b = fun2();
向下转型(Downcasting)
把父类引用强制转回子类引用,就是向下转型。
1 | Animal a = new Dog(); // 先向上转型 |
几个要点:
必须显式强制转换,写
(Dog)。有风险。如果对象本来不是
Dog,运行时会抛ClassCastException:1
2Animal a = new Animal(); // 创建一个 a 是 Animal对象,不是 Dog 对象
Dog d = (Dog) a; // 编译能过,运行时崩溃!转之前用
instanceof检查更安全:1
2
3
4if (a instanceof Dog) {
Dog d = (Dog) a;
d.bark();
}
总结
继承
- 子类自动获得父类的方法和属性。
Dog extends Animal,所以 Dog 天生就有 eat() 方法
多态
- 父类引用调用方法时,实际执行的是子类重写后的版本
向上转型
- 把子类对象赋值给父类引用
向下转型
- 把父类引用强制转回子类引用



