
想象一下我们要描述狗和猫这两种动物。如果不使用继承,代码可能会是这样:
// Dog.java
public class Dog {
String name;
int age;
float weight;
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
void bark() {
System.out.println(name + "汪汪汪---");
}
}
// Cat.java
public class Cat {
String name;
int age;
float weight;
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
void mew() {
System.out.println(name + "喵喵喵---");
}
}
可以看到,这两个类中有大量重复的代码(name、age、weight属性,eat()和sleep()方法)。继承机制正是为了解决这种代码冗余问题而生的。
继承是面向对象程序设计使代码可以复用的最重要手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能。这样产生的新类称为派生类(子类),被继承的类称为基类(父类)。
继承关系可以用以下图示表示:
Animal
/ \
Dog Cat在Java中使用extends关键字实现继承:
// Animal.java
public class Animal {
String name;
int age;
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
}
// Dog.java
public class Dog extends Animal {
void bark() {
System.out.println(name + "汪汪汪---");
}
}
// Cat.java
public class Cat extends Animal {
void mew() {
System.out.println(name + "喵喵喵---");
}
}在继承体系中,子类可以访问父类的成员,但有一些规则需要注意:
当子类和父类有同名成员时,可以使用super关键字显式访问父类的成员:
public class Derived extends Base {
int a; // 与父类同名
public void method() {
super.a = 200; // 访问父类的a
this.a = 100; // 访问子类的a
}
}子类构造时必须先调用父类构造方法:
public class Base {
public Base() {
System.out.println("Base()");
}
}
public class Derived extends Base {
public Derived() {
// 编译器会自动添加super();
System.out.println("Derived()");
}
}注意:
super()必须是子类构造方法的第一条语句在现实生活中,事物之间的关系是非常复杂,灵活多样,比如:

但在Java中只支持这几种继承方式

多态是指同一行为在不同对象上表现出不同的形态。例如:
打印机
├─ 彩色打印机 → 打印效果:彩色
└─ 黑白打印机 → 打印效果:黑白Java中实现多态需要满足三个条件:
区别点 | 重写(override) | 重载(overload) |
|---|---|---|
参数列表 | 一定不能修改 | 必须修改 |
返回类型 | 不能修改(除非构成父子类关系) | 可以修改 |
访问限定符 | 不能做更严格的限制(可以降低限制) | 可以修改 |
重载和重写的区别:

重写是子类对父类方法的重新实现,必须遵循以下规则:
示例:
class Animal {
public void eat() {
System.out.println("动物吃饭");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}向上转型:子类对象赋值给父类引用
Animal animal = new Cat("咪咪", 2);向下转型:父类引用强制转换为子类类型

if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.mew();
}优点:
缺点:
看一个典型问题:
class B {
public B() {
func(); // 危险!
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D(); // 输出:D.func() 0
}
}此时num还未初始化(值为0),因为父类构造方法执行时子类字段还未初始化。
继承表示"is-a"关系,组合表示"has-a"关系。例如:
// 继承:奔驰是汽车
class Benz extends Car {
// ...
}
// 组合:汽车有发动机、轮胎等
class Car {
private Engine engine;
private Tire tire;
// ...
}设计原则:优先使用组合,除非明显是"is-a"关系。
final可以修饰:
final class String { // String类不可继承
// ...
}【使用多态的好处】 能够降低代码的 “圈复杂度”, 避免使用大量的 if - else 什么叫 “圈复杂度” ? 圈复杂度是一种描述一段代码复杂程度的方式. 一段代码如果平铺直叙, 那么就比较简单容易理解. 而如果有很多的条件分支或者循环语句, 就认为理解起来更复杂.因此我们可以简单粗暴的计算一段代码中条件语句和循环语句出现的个数, 这个个数就称为 “圈复杂度”.如果一个方法的圈复杂度太高, 就需要考虑重构.
继承和多态是Java面向对象编程的核心概念,掌握它们对于写出优雅、灵活的代码至关重要。记住: