我们先从生活中的例子开始思考:为什么猫和狗都属于“动物”,而不是单独定义两套完全相同的代码?这时候,“继承”就派上用场了!继承的核心思想是子类可以复用父类的属性和方法,同时扩展自己的功能。想象一下,猫和狗都是动物(父类),它们天生就继承了“动物”的共同特点(比如会呼吸、会吃饭),同时每个子类又有自己独特的行为(比如猫会抓老鼠,狗会看家)。这种“我有的你也有,我有的你还能更好”的关系,就是继承要解决的问题。
1. 继承的基本语法:子类 extends 父类¶
要实现继承,需要先定义一个父类,再用extends关键字定义子类,让子类继承父类的属性和方法。
举个例子:
// 父类:动物(定义共同特征)
class Animal {
// 父类的属性(成员变量):动物都有名字和年龄
String name;
int age;
// 父类的方法(成员方法):动物的共同行为
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
}
// 子类:猫(继承动物的特征)
class Cat extends Animal {
// 子类可以添加自己的属性/方法(猫特有的行为)
String color; // 猫的颜色
public void catchMouse() {
System.out.println(name + "正在抓老鼠!");
}
}
关键点:¶
- 父类(Animal):定义共性特征(属性和方法)。
- 子类(Cat):用
extends关键字继承父类,获得父类的所有非private属性和方法,并可添加自己的功能。
2. 子类能继承什么?不能继承什么?¶
子类继承父类后,会自动获得:
- 父类的非private属性(成员变量)。
- 父类的非private方法(成员方法)。
注意:父类中被private修饰的属性/方法,子类无法直接访问!如果需要访问,必须通过父类的public或protected方法(如getter/setter)。
class Animal {
private String name; // 私有属性,子类无法直接访问
// 父类提供公共方法访问私有属性
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Cat extends Animal {
public void test() {
// 直接访问父类的name会报错!必须通过父类的方法
// System.out.println(name); // 错误!
System.out.println(getName()); // 正确:通过父类的public方法访问
}
}
3. 继承的核心:“is-a”关系¶
继承不是随便用的!子类和父类必须是“is-a”关系(子类是父类的一种)。
- ✅ 正确:猫是动物 →
Cat extends Animal(猫“是”动物)。 - ❌ 错误:如果关系是“猫有爪子”(has-a关系),应该用组合而非继承。
比如:
// 正确:学生是人类的一种(is-a)
class Student extends Person {}
// 错误:轮子不是交通工具的一种(has-a关系)
// class Wheel extends Vehicle {}
4. 方法重写(Override):子类“个性化”父类方法¶
子类可以重写父类的方法,即修改方法的实现逻辑,但保持方法签名(返回值、参数列表)不变。
例子:父类Animal有一个makeSound()方法,子类Cat和Dog分别重写这个方法实现不同的叫声。
class Animal {
public void makeSound() {
System.out.println("动物发出叫声");
}
}
class Cat extends Animal {
// 重写父类的makeSound方法
@Override // 注解:告诉编译器这是方法重写(可选但建议加)
public void makeSound() {
System.out.println("喵喵喵~");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪!");
}
}
测试:¶
Cat myCat = new Cat();
myCat.makeSound(); // 输出:喵喵喵~
Dog myDog = new Dog();
myDog.makeSound(); // 输出:汪汪汪!
5. super关键字:调用父类的“我”¶
super是Java关键字,用于调用父类的属性、方法或构造方法。
5.1 调用父类的属性/方法¶
如果子类和父类有同名属性/方法,用super明确指定调用父类:
class Animal {
String name = "动物";
public void info() {
System.out.println("我是" + name);
}
}
class Cat extends Animal {
String name = "猫"; // 子类同名属性
public void showInfo() {
System.out.println("子类name:" + name); // 调用子类属性
System.out.println("父类name:" + super.name); // 调用父类属性
}
}
5.2 调用父类的构造方法¶
子类构造方法中,super()必须放在第一行,用于调用父类的构造方法:
class Animal {
String name;
public Animal(String name) { // 父类带参构造
this.name = name;
}
}
class Cat extends Animal {
public Cat(String name) {
super(name); // 必须先调用父类构造方法
this.name = name;
}
}
6. 继承的优点和注意事项¶
优点:¶
- 代码复用:父类定义共性,子类直接继承,避免重复写代码。
- 扩展性:子类可在父类基础上添加新功能(如
Cat新增catchMouse()方法)。 - 结构清晰:通过继承形成类的层次关系(如动物→猫→中华田园猫)。
注意事项:¶
- 单继承:Java类只能单继承(一个子类只能有一个直接父类),但支持多层继承(子类的子类)。
- private成员不可直接访问:父类
private属性/方法需通过public方法访问。 - 方法重写规则:子类方法的返回值类型、参数列表必须与父类完全一致(协变返回值除外,如父类返回Object,子类返回String)。
总结¶
继承是Java面向对象的核心特性,通过extends关键字实现子类继承父类的属性和方法。关键记住:
- 继承的核心是“is-a”关系,子类必须是父类的一种。
- 子类可重写父类方法,通过super调用父类成员。
- 继承让代码更简洁、复用性更强,是实现代码扩展和维护的重要手段。
现在你可以尝试定义自己的父类和子类,比如“人(Person)”作为父类,“学生(Student)”作为子类,体验继承的魅力吧!