extends 关键字继承父类,语法为
class 子类名 extends 父类名 {...},可重写父类方法、访问
继承
Java中,extends关键字是实现类之间继承关系的核心机制,它体现了面向对象编程中的IS-A语义(即子类是一种更具体的父类类型),以下是关于如何使用extends的详细说明:
基本语法规则
定义子类时,通过class Subclass extends Superclass的形式声明继承关系。
class Animal { // 父类/超类
String name;
void eat() { ... }
}
class Dog extends Animal { // 子类继承自Animal
// 新增成员或重写方法
}
Dog自动获得Animal的所有非私有属性和方法(如字段name和行为eat()),同时可以扩展自己的功能,这种单继承特性确保每个子类仅有一个直接父类,避免了C++中的多重继承混乱问题。
关键特性解析
| 特性 | 说明 | 示例 |
|---|---|---|
| 成员变量继承 | 子类可直接访问父类的protected/public成员 | Dog d = new Dog(); d.name = "Buddy"; |
| 方法覆盖(Override) | 子类能重新定义父类的方法以实现多态 | @Override void bark() { System.out.println("汪汪"); } |
| 构造函数调用链 | 必须显式/隐式调用父类构造器(使用super()) | public Dog() { super(); } |
| 类型兼容性 | 向上转型允许将子类实例赋值给父类引用 | Animal a = new Dog(); a.eat(); |
| 访问权限限制 | private成员不被继承,默认修饰符仅在同一包内可见 | 父类的私有数据需通过公共方法间接操作 |
典型应用场景
代码复用与层次化设计
通过继承构建类层级结构,减少重复代码,例如图形系统中:
abstract class Shape {
void draw() { /通用绘制逻辑/ }
}
class Circle extends Shape { ... }
class Square extends Shape { ... }
所有形状共享基础绘图能力,而具体实现由子类完成。
多态行为模拟
结合方法重写实现动态绑定:
void interact(Animal obj) { // 参数为父类类型
obj.makeSound(); // 实际调用的是子类的实现
}
interact(new Dog()); // 输出"汪汪"而非默认的动物叫声
框架扩展点
许多库利用继承提供扩展能力,如Android中的View组件定制:
public class MyButton extends android.widget.Button {
// 添加自定义样式或行为
}
常见误区规避
️ 错误示范1:试图继承final类
若父类被声明为final(如String),则无法被继承,编译器会直接报错:“Cannot extend final class”,解决方案是改用组合模式替代继承。
️ 错误示范2:过度依赖继承导致耦合度过高
当需要多个“身份”时(例如既想飞又想游泳),优先使用接口实现而非强制单继承:
// 不良设计
class FlyingFish extends Fish implements Flyable { ... }
// 推荐方案
interface Flyer { void fly(); }
class FlyingFish implements FishBehavior, Flyer { ... }
️ 错误示范3:忽略父类构造函数初始化
未正确调用super()可能导致父类状态异常。
class Person {
String idCard; // 必须在构造时分配
public Person(String num) { this.idCard = num; }
}
class Student extends Person {
public Student() { } // 编译错误!必须显式调用父类有参构造器
}
应修改为:public Student() { super("STU_"); }
进阶技巧
抽象类的强制规范
使用abstract修饰符定义不完全模板类,强制子类实现特定方法:
abstract class Appliance {
abstract void turnOn(); // 无具体实现
void plugIn() { ... } // 公共逻辑保留
}
class WashingMachine extends Appliance {
@Override void turnOn() { /实现通电启动/ }
}
泛型约束下的继承
在集合框架中使用通配符限定类型范围:
List<? extends Number> numList = new ArrayList<Integer>(); // 允许添加null但禁止其他类型元素
此处? extends Number表示接受任何Number子类型的列表(如Integer、Double等)。
与接口的区别决策树
| 条件 | 选择extends | 选择implements |
|---|---|---|
| 是否存在具体实现需求 | ||
| 是否需要多“角色”支持 | (接口可多实现) | |
| 是否属于自然分类关系 | (如猫→动物) | |
| 是否需要版本兼容升级 | (接口演化不影响旧代码) |
FAQs
Q1: Java为什么不允许多重继承?如何突破限制?
答:Java为避免菱形继承歧义(如两个父类的同名方法冲突),采用单继承+多接口实现的方式,若需类似效果,可通过内部类包装或接口组合达成。
interface Swim {}
interface Fly {}
class Duck implements Swim, Fly { ... }
Q2: 子类构造函数中super()的位置有何讲究?
答:根据Java规范,子类构造器的第一行必须是对父类构造器的调用(默认为无参super()),若父类没有默认构造器,则必须在子类构造器中显式指定参数匹配的super调用。
class Base { public Base(int x) {...} }
class Derived extends Base {
public Derived() { super(42); } // 正确写法
}
