钩子:两段几乎一样的代码
上篇封装完的 Student,现在新来一个 Employee 类:
class Employee {
private String name; // 和 Student 一模一样
private int age; // 和 Student 一模一样
private double salary; // 多出来的
public String getName() { return name; } // 一模一样
public void setAge(int age) { ... } // 一模一样
}
name、age、getter、setter——一大半代码是复制粘贴的。复制第三遍的时候你就该警觉了:这是重复代码,是维护灾难的种子(改一处漏一处)。
Java 的解法:把共同部分抽出来,放到一个父类里。
核心:extends——"是一种"关系
class Person {
private String name;
private int age;
public String getName() { return name; }
public void setAge(int age) {
if (age < 0 || age > 150) return; // 校验只写一遍
this.age = age;
}
}
class Student extends Person { // 学生"是一种"人
private String school;
}
class Employee extends Person { // 员工"是一种"人
private double salary;
}
extends 一个词,Student 和 Employee 自动拥有了 Person 的 name、age 和全部 public 方法。校验逻辑只写一遍,三个类共享。

判断能不能继承,就一句话:子类必须"是一种"父类(is-a)。 学生是一种人 ✔,狗是一种动物 ✔;但"汽车是一种发动机" ✘(汽车"有"发动机,那是组成关系,不该继承)。is-a 就继承,has-a 就把对方做成字段——这一条能帮你避开 90% 的继承烂设计。
方法重写:继承来了,但我想"改台词"
父类 Person 有 introduce() 方法(自我介绍),Student 想多说一句学校:
class Person {
public void introduce() {
System.out.println("我叫" + name);
}
}
class Student extends Person {
@Override
public void introduce() {
super.introduce(); // 先说父类那句
System.out.println("我在" + school + "上学");
}
}
重写(Override):子类提供一个和父类方法签名完全相同的方法,把父类的"台词"改掉。注意两点:
- @Override 注解建议永远手写——它让编译器帮你检查"是不是真的重写了"。拼错方法名(比如写成 introduc),没加 @Override 就是悄悄新增了一个方法,加了立刻报错。这是新手重写翻车的第一名;
- super.introduce() 表示"借用父类的版本"——super 和 this 长得像,this 指"我自己",super 指"我爹的那份"。
两个必懂细节
- 构造方法不被继承,但子类构造时一定会先执行父类构造——子类构造第一行若不写,编译器自动补一句
super()。这就是为什么父类若只写了有参构造,子类构造会报错(第 15 篇"默认构造被收回"的连锁反应); - private 字段被子类"继承"但不可直接访问——拿到了房子,但保险柜的钥匙在父类手里,子类只能走 getter/setter 这扇门。
本文示例代码均已本地实测通过,可直接运行。
对应文件:InheritDemo.java
橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。