java继承详解
Java 继承详解 | 菜鸟教程 (runoob.com)
Java 继承 | 菜鸟教程 (runoob.com)
什么是继承?
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
多个类可以称为子类,单独这个类称为父类、超类或者基类。使用extends关键词
class 父类 {
}class 子类 extends 父类 {
}
继承之后,子类自动拥有父类的属性与方法(一般,有部分特殊情况)
继承的特点
1.Java只支持单继承,不支持多继承。
//一个类只能有一个父类,不可以有多个父类。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error
2.Java支持多层(重)继承(继承体系)。
class A{}
class B extends A{}
class C extends B{}
super,this关键字
super是一个关键字,代表父类的存储空间标识。(可以理解为父亲的引用)
super和this的用法相似,可以用来在子类中访问父类的元素
注意:
- 不能访问父类private修饰的属性与方法
- 可以访问父类构造器
- super,this的访问遵循逐级向上查找,就近原则(下文链接中会提到)
继承注意事项
访问修饰符
子类拥有父类非 private 的属性、方法。
子类不能访问父类中由private修饰的属性与方法
java.lang.object
所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承 Object(这个类在 java.lang 包中,所以不需要 import)祖先类。
final关键字
修饰类
- final类:一旦一个类被声明为final,它就不能被继承。这意味着你不能创建该类的子类。例如:
final class MyFinalClass {// 类的方法和变量 }
修饰方法
- final方法:一旦一个方法被声明为final,它就不能被重写(override)。这意味着子类不能改变该方法的行为。例如:
public class MyClass {public final void myFinalMethod() {// 方法体} }
修饰变量
- final成员变量:一旦一个成员变量被声明为final,它的值就不能被改变。这意味着你必须在声明变量时或构造函数中为其赋值。例如:
public class MyClass {private final int myFinalVariable;public MyClass(int value) {myFinalVariable = value;} }
- final局部变量:在方法内部,你可以声明一个final局部变量,这意味着在方法内部,该变量的值不能被改变。例如:
public void myMethod() {final int myFinalLocalVariable = 10;// myFinalLocalVariable的值不能被改变 }
构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
class SuperClass {private int n;// 无参数构造器public SuperClass() {System.out.println("SuperClass()");}// 带参数构造器public SuperClass(int n) {System.out.println("SuperClass(int n)");this.n = n;}
}// SubClass 类继承
class SubClass extends SuperClass {private int n;// 无参数构造器,自动调用父类的无参数构造器public SubClass() {System.out.println("SubClass()");}// 带参数构造器,调用父类中带有参数的构造器public SubClass(int n) {super(300);System.out.println("SubClass(int n): " + n);this.n = n;}
}// SubClass2 类继承
class SubClass2 extends SuperClass {private int n;// 无参数构造器,调用父类中带有参数的构造器public SubClass2() {super(300);System.out.println("SubClass2()");}// 带参数构造器,自动调用父类的无参数构造器public SubClass2(int n) {System.out.println("SubClass2(int n): " + n);this.n = n;}
}public class TestSuperSub {public static void main(String[] args) {System.out.println("------SubClass 类继承------");SubClass sc1 = new SubClass();SubClass sc2 = new SubClass(100);System.out.println("------SubClass2 类继承------");SubClass2 sc3 = new SubClass2();SubClass2 sc4 = new SubClass2(200);}
}
所以一般来说父类与子类初始化的顺序是
父类静态代码块→子类静态代码块→父类构造代码块→父类构造方法→子类构造代码块→子类构造方法
方法重写
子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写。但是父类的私有方法无法重写。因为父类私有方法,子类看不到,因此父类私有方法的重写也就无从谈起。
覆盖注意事项:
- 覆盖时,子类方法权限一定要大于等于父类方法权限;
- 静态只能覆盖静态。
- 参数列表得一样,但是返回类型可以不一样。重写的方法返回类型必须是原方法的子类。例如string 与 object
覆盖的使用场景:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,既沿袭了父类的功能,又定义了子类特有的内容。
继承的内存布局
0293_韩顺平Java_继承本质详解_哔哩哔哩_bilibili
![[Pasted image 20240826192255.png]]
如何通过通过子类访问父类
0293_韩顺平Java_继承本质详解_哔哩哔哩_bilibili