Java基础——继承
前言:
在面向对象编程中,继承是实现代码复用,建立类之间层次关系的重要机制。通过继承,我们可以将多个类的公共部分抽取到父类中,子类只需要关注自己特有的属性和行为,从而让代码更加简洁,易于维护。
本文将从为什么需要继承讲起,详细解析java中继承的语法,成员访问规则,super关键字,构造方法互动,protected访问权限,代码块初始化顺序,final的限制作用。
目录
一.为什么需要继承——代码的复用
设想我们有两个类:Dog和Cat,它们都有姓名,年龄,体重,都会吃饭睡觉。如果不使用继承,我们需要在两个类中重复编写同样的字段和方法:
//Dog.java
public class Dog{
String name;
int age ;
float weight;
public void eat(){
System.out.println(name+"正在吃饭");
}
public void sleep(){
System.out.println(name+"正在睡觉");
}
void bark() {
System.out.println(name + "汪汪汪~~~");
}
}
//Cat.java
public class Cat {
String name;
int age;
float weight;
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
void mew() {
System.out.println(name + "喵喵喵~~~");
}
}
大量的代码重复,这不仅导致代码臃肿,也增加了维护成本——如果要修改动物的通用行为,必须要去修改每个类。
面向对象编程为我们提供了解决方案:继承。继承允许我们抽取共性,形成层次结构,让子类自动拥有父类的特性,从而实现“站在巨人的肩膀上”编程。
二.继承的基本语法
2.1什么是继承?
继承是面向对象程序设计中实现代码复用的重要手段。它允许程序员在保持原有类特性的基础上进行拓展,增加新功能。
父类:被继承的类,代表共性。
子类:继承父类的类,代表个性。
2.2 extends关键字
在Java中,使用extends关键字来表示继承关系。
语法:
修饰符 class 子类 extends 父类{ //子类内容 }
示例:
// Animal.java (父类)
public class Animal {
String name;
int age;
public void eat() {
System.out.println(name + "正在吃饭");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
}
// Dog.java (子类)
public class Dog extends Animal {
void bark() {
System.out.println(name + "汪汪汪~~~");
}
}
// Cat.java (子类)
public class Cat extends Animal {
void mew() {
System.out.println(name + "喵喵喵~~~");
}
}
// 测试
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财";
dog.eat(); // 继承自Animal
dog.bark(); // 自己的方法
}
}
我们通常会将字段设为private,并通过protected的getter/setter方法来访问,以符合严格的封装原则。
注意:子类应添加自己特有的成员,否则单纯继承无意义。
三.父类成员访问规则
3.1成员变量访问:就近原则
无同名变量:子类直接访问继承来的变量。
有同名变量:遵循就近原则,优先访问子类的自己的变量。
public class Base{
int a=10;
int b=20;
}
public class Derived extends Base{
int a=100; //同名变量
public void method(){
System.out.println(a); //输出子类的a 100
System.out.println(b); //输出父类的b 20
}
}
若想强制访问父类的同名成员,需要使用super关键字。
3.2成员方法访问
方法名不同:先找子类,再找父类,找不到编译报错。
方法名:相同(重写/重载):
若参数列表不同(重载),根据调用参数决定。
若参数列表完全相同(重写),则有限调用子类的方法(多态特性)。
重写(Override)要求方法名,返回类型,参数列表完全一致,子类访问权限不能严于父类。
四.super关键字:显示访问父类成员
当子类和父类出现相同名字的成员时,super可以帮我们访问父类的成员。
public class Derived extends Base {
int a = 100;
public void method() {
System.out.println(a); // 子类自己的 a
System.out.println(super.a);// 父类的 a
super.methodA(); // 调用父类方法
}
}
super的三大用法
1.访问父类的成员变量:super.父类变量名
2.访问父类的成员方法:super.父类方法名()
3.调用父类的构造方法:super(参数列表)
五.子类构造方法与super()调用链
核心原则:先有父,再有子
子类对象包含两部分:从父类继承下俩的成员+自己新增的成员。因此,构造子类对象之前必须先构造父类对象。
规则详解:
默认调用:如果子类构造方法中没有显式写super(),编译器会自动插入super,即调用父类的无参构造方法。
显式调用:如果父类没有无参构造(例如定义了带参构造),子类必须再第一行显式调用super(参数)。
唯一性和顺序:super()必须是子类构造方法中的第一条语句,且只能出现一次。
public class Base{
public Base(int a ){
System.out.println("Base构造"+a);
}
}
public class Derived extends Base{
public Derived(){
super(10); //必须显式调用,且位于第一行
System.out.println("Derived 构造")
}
}
super()只能在子类构造方法中使用,且必须是第一条语句。
super()和this()不能同时出现(因为都要在第一行)。
若父类没有无参构造,子类未显式调用父类其他构造方法,编译报错。
六.super和this的对比
| this | super | |
| 本质 | 当前对象的引用 | 子类对象中父类部分的引用 |
| 访问范围 | 本类的成员 | 父类的成员 |
| 构造方法的调用 |
this(...)调用本类其他 构造方法 |
super(...)调用父类构造方法 |
| 是否必须第一行 | 是,与super()排斥 | 是,与this排斥 |
| 是否默认存在 | 除非手动调用this |
子类构造方法中默认有super() 父类有无参构造时 |
七.继承关系下的初始化顺序(时间轴)
“静态优先,父先子后” 父静-->子静-->父实-->父构-->子实-->子构
静态代码块:只执行一次,在类加载的时执行。父类优先于子类。
实例代码块:每次创建对象时。父类的实例块在父类构造方法之前执行
构造方法:最后执行。
class Person {
public Person(String name, int age) {
System.out.println("Person构造");
}
{ System.out.println("Person实例代码块"); }
static { System.out.println("Person静态代码块"); }
}
class Student extends Person {
public Student(String name, int age) {
super(name, age);
System.out.println("Student构造");
}
{ System.out.println("Student实例代码块"); }
static { System.out.println("Student静态代码块"); }
}
public class Test {
public static void main(String[] args) {
new Student("张三", 19);
System.out.println("============");
new Student("李四", 20);
}
}
八.protected访问权限
protected允许:
同一个包中的任何类访问。
不同包中的子类访问从父类继承下来的protected成员。
注意:在不同包的子类中,不能通过其他子类对象访问其protected成员
// 包 demo1
public class Base {
protected int b = 100;
}
// 包 demo2
import demo1.Base;
public class Derived extends Base {
void test() {
System.out.println(b); // OK,继承下来的 protected
Base obj = new Base();
// System.out.println(obj.b); // 错误!不同包中不能通过父类对象访问 protected
}
}
九.final关键字:继承的“终结者”
为了防止类被继承或方法被重写,java提供了final。
修饰类:该类不能被继承(如String类)
修饰方法:该方法不能被重写。
修饰变量:变量为常量,不能被修改。
final class Animal { } // 不可被继承
// class Dog extends Animal { } // 编译错误
class Parent {
final void method() { }
}
class Child extends Parent {
// void method() { } // 编译错误,不能重写 final 方法
}
总结:
语法基础:extends和super的使用
底层逻辑:构造方法的调用链和初始化顺序
访问控制:protected允许不同包子类访问,但不能通过其他子类对象访问。
限制手段:final可以限制继承,重写,修改
更多推荐

所有评论(0)