继承是Java中的一个重要概念,它允许创建分等级层次的类,描述的是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。在继承中有连个重点:`转型`、`动态绑定和静态绑定`,在此之前,笔者对第二个概念似懂非懂,但是经过一番查阅和实操发现原来也就那么回事儿嘛:new_moon_with_face:
首先,抛出一个问题:下面代码执行后会输出什么?
```java
class Father{
public static void name(){
System.out.println("Father");
}
public void realName(){
System.out.println("Father");
}
}
class Son extends Father{
public static void name(){
System.out.println("Son");
}
public void realName(){
System.out.println("Son");
}
public void age(){
System.out.println("Son age");
}
}
public class HelloWorld {
public static void main(String []args) {
Father son = new Son();
son.name();
son.realName();
}
}
```
答案是:
```java
Father
Son
```
接下来详细介绍一下这其中的弯弯角角。
### 转型
当子类对象的引用指向父类对象或父类对象的引用指向子类对象时就会涉及到类型转型,转型有两种:
- 向上转型(upcasting):子类型->父类型,又叫自动类型转换
- 向下转型(downcasting):父类型->子类型,又叫强制类型转换(要加强制类型转换符)
转型比较简单,例如上例中`Father son = new Son();`就属于向上转型;如果写成`Son father = (Son) new Father();`就属于向下转型,这是就需要强制类型性转换。
需要注意的是在向上类型转化后得到的对象实例只能调用父类中的方法,不能调用父类中没有但子类中创建的方法。例如当父类对象的引用指向子类时`Father son = new Son();`那么`son.age();`就会编译不通过,原因是Father类中没有定义`age()`方法。
```java
Error:(32, 12) java: 找不到符号
符号: 方法 age()
位置: 类型为test.Father的变量 son
```
### 动态绑定和静态绑定
动态绑定静态绑定是针对非静态方法/变量和静态方法/变量而言的。父类的非静态方法可以被重写,但静态方法不能被重写。向上转型后的父类对象在调用被子类重写的方法时会动态绑定到子类所实现的方法上;调用静态方法是会静态绑定到自己类的静态方法上,这也就是为什么上例中`son.name();`会输出`Father`,`son.realName();`会输出`Son`。

Java继承中的子类/父类对象交叉引用问题总结