java中extends的基本写法是class子类名extends父类名,仅支持单继承;子类自动继承父类非private成员,重写方法需签名一致且访问权限不更严格,构造器中用super()调用父类构造。

Java 中 extends 的基本写法和继承关系确认
Java 类继承必须显式用 extends 关键字声明,且一个类只能直接继承一个父类(不支持多继承)。子类会自动获得父类的非私有成员(public、protected、包内默认访问权限的字段和方法),但 private 成员不可见,也不能被重写。
常见错误是误以为子类能直接访问父类的 private 字段——实际会编译报错:error: cannot find symbol。此时应通过父类提供的 public 或 protected getter/setter 访问。
- 父类构造器不会被继承,但子类构造器默认第一行隐式调用
super();若父类无无参构造器,子类必须显式写super(...) - 子类重写父类方法时,访问修饰符不能比父类更严格(例如父类是
protected,子类不能写private) - 使用
instanceof可验证继承关系,如new Dog() instanceof Animal返回true
如何正确重写(Override)父类方法并调用父类实现
重写不是覆盖,而是对父类行为的定制。必须满足:方法名、参数列表、返回类型(或协变返回类型)完全一致,且不能降低访问权限。IDE 通常会提示 @Override 注解,它不只是装饰——加了它,编译器会检查是否真正在重写,避免拼写错误导致“意外新建方法”。
如果需要在子类方法中复用父类逻辑,用 super.methodName() 显式调用。漏掉 super 是新手高频坑,比如初始化资源时忘记调用父类 init(),导致父类状态未就绪。
class Animal {
void speak() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override
void speak() {
super.speak(); // 输出 "Some sound"
System.out.println("Woof!"); // 再输出 "Woof!"
}
}
继承中字段隐藏(Field Hiding)与方法重写的区别
字段不能被重写,只能被隐藏。当子类定义了与父类同名的字段(尤其同类型),子类对象中会存在两个独立字段:访问取决于引用类型,而非实际对象类型。这和方法重写的动态绑定完全不同,极易引发逻辑混乱。
例如:Animal a = new Dog(); System.out.println(a.name); 输出的是父类的 name 值,而 ((Dog)a).name 才是子类的值。这种歧义几乎总是设计缺陷,应避免同名字段。
- 方法调用看实际对象类型(运行时决定),字段访问看引用类型(编译时决定)
- 若需统一管理属性,应将字段设为
private,并通过protected或public方法暴露 -
final方法不能被重写,static方法只能被“隐藏”,不是重写
什么时候不该用 extends?优先考虑组合
继承表达的是“is-a”关系(Dog is an Animal),不是“has-a”。如果只是为了复用代码而强行拉出父类,比如让 Car 继承 Engine,就违背语义,后续扩展会越来越僵硬。
多数场景下,用组合(把对象作为字段持有)更灵活、更易测试、更少耦合。例如 Car 持有 Engine 实例,而不是继承它;需要换引擎时只需替换字段,不用改类结构。
继承链过深(超过 2~3 层)也是危险信号:修改顶层类可能意外影响所有下游子类,且 protected 成员越多,封装性越差。JDK 自身也倾向组合,比如 ArrayList 内部用 Object[] 而非继承数组。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











