Java extends 程序学习笔记
作者:小沙盒工作室
下面是一份可以直接存进你笔记的程序笔记,我按"概念+代码+易错点"的方式写,重点把你关心的extends、字段继承/隐藏、方法重写、重载这几件事彻底理清
一、extends 的本质
一句话:extends 表达"是一个(is-a)"关系,核心价值是复用 + 多态。
class Dog extends Animal { }
// 读作:狗是一种动物使用前先自问:子类真的是父类的一种吗?
- 是 → 可以考虑继承
- 不是 → 用组合(has-a)
二、extends 带来的两样东西
1. 复用(字段和方法继承下来直接用)
class Animal {
String name;
int age;
}
class Cat extends Animal { } // 自动拥有 name、age
class Dog extends Animal { } // 自动拥有 name、ageCat、Dog 不用再声明 name、age,直接拥有。
注意:字段是"继承",不是"重写"。字段没有重写这回事。
2. 多态(父类引用,子类对象)
Animal a = new Cat(); a.speak(); // 运行时调用 Cat 的 speak
- 编译时看引用类型(Animal)
- 运行时看实际对象(Cat)
三、字段 vs 方法(最容易混的地方)
| 项目 | 字段(成员变量) | 方法 |
|---|---|---|
| 能否被继承 | 能,直接用 | 能,可直接调用 |
| 能否被"重写" | 不能,只有隐藏 | 能,Override |
| 同名时决定看谁 | 编译时看引用类型 | 运行时看实际对象 |
| 和多态关系 | 无 | 多态的基础 |
一句话记:字段看左边(引用类型),方法看右边(实际对象)。
四、字段隐藏(field hiding)
子类声明了和父类同名的字段,不是重写,是隐藏。
class Animal {
String name = "动物";
}
class Cat extends Animal {
String name = "猫"; // 同名,隐藏父类字段
}
Cat c = new Cat();
System.out.println(c.name); // 猫
Animal a = c;
System.out.println(a.name); // 动物 ← 同一个对象!结论:同一个对象,用不同引用类型看,字段值可能不同。这是 bug 高发区。
建议:实际开发中不要写同名字段,避免隐藏。
五、方法重写(Override)
子类重新实现父类的方法,这才有多态。
class Animal {
void speak() { System.out.println("某种声音"); }
}
class Cat extends Animal {
@Override
void speak() { System.out.println("喵"); }
}规则:
- 方法名、参数列表、返回类型必须一致
- 访问权限不能比父类更严格
- 加
@Override让编译器帮你检查
重写改的是"行为",不是"字段"。
六、方法重载(Overload)
同一个类里,方法名相同、参数列表不同。
class Calc {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
}规则:
- 同一个类中
- 方法名相同
- 参数列表不同(个数 / 类型 / 顺序)
- 与返回类型无关
重载是编译时决定,跟多态无关。
七、重写 vs 重载(必须分清)
| 重写 Override | 重载 Overload | |
|---|---|---|
| 位置 | 子类重写父类方法 | 同一个类中 |
| 方法名 | 相同 | 相同 |
| 参数列表 | 必须相同 | 必须不同 |
| 返回类型 | 相同或兼容 | 无关 |
| 决定时机 | 运行时(多态) | 编译时 |
| 作用 | 改变行为,实现多态 | 提供多种调用方式 |
八、this / super
class Cat extends Animal {
String name = "猫";
void show() {
System.out.println(name); // 本类 name → 猫
System.out.println(super.name); // 父类 name → 动物
}
}this指当前对象,super指父类部分- 字段隐藏时,用
super.字段访问父类字段
九、抽象类与契约
abstract class Animal {
abstract void speak(); // 只声明,不实现,强制子类实现
}- 抽象类不能
new - 子类必须实现所有抽象方法,否则子类也得是抽象的
- 父类定义"必须有什么能力",子类决定"怎么做"
这就是继承的契约:既然是我的子类,就必须保证这个能力。
十、什么时候不该用 extends
- 只是想复用代码 → 用组合
- 子类不是父类的"一种" → 用组合
- 父类行为子类无法全部满足(如企鹅 extends 会飞的鸟)→ 父类抽象错了
- 继承层次超过 2~3 层 → 通常设计有问题
原则:优先使用组合,而不是继承。
// 组合:has-a
class Penguin {
private Bird bird = new Bird(); // 借用能力,不继承
}十一、完整示例(建议敲一遍)
abstract class Shape {
String name = "形状";
abstract double area();
}
class Circle extends Shape {
String name = "圆"; // 隐藏父类字段
double r = 1;
@Override
double area() { return Math.PI * r * r; }
}
class Rect extends Shape {
double w = 2, h = 3;
@Override
double area() { return w * h; }
}
public class Test {
public static void main(String[] args) {
Shape[] shapes = { new Circle(), new Rect() };
double total = 0;
for (Shape s : shapes) {
total += s.area(); // 多态:运行时决定调用谁
}
System.out.println(total);
Circle c = new Circle();
System.out.println(c.name); // 圆 (看左边类型 Circle)
Shape s = c;
System.out.println(s.name); // 形状 (看左边类型 Shape)
}
}实验重点:
s.area()调的是子类方法 → 方法看运行时对象c.name和s.name输出不同 → 字段看编译时引用类型- 新增 Triangle,total 那段代码不用改 → 这就是 extends 的意义
十二、核心结论(背这五条)
- extends = is-a,先判断是不是"一种",不是就用组合。
- 字段靠继承,方法靠重写;字段没有重写,只有隐藏。
- 字段看左边(引用类型),方法看右边(实际对象)。
- 重写(Override)实现多态,重载(Overload)只是同名不同参。
- 优先组合,慎用继承;父类抽象错了,继承就是灾难。
需要的话,我可以把这份笔记再压缩成一页速查表,或者出几道判断对错的练习题帮你自测。
到此这篇关于Java extends 程序笔记的文章就介绍到这了,更多相关Java extends 程序笔记内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
