抽象类(通用)
子类继承父类方法后,这个子类对象如果执行方法的话,只要子类重写了就执行子类的,不执行父类的。
/**
* 功能:
* 作者:IT伟
* 日期:2025/1/13 19:20
*/
// 抽象类 A
abstract class A {
// 构造函数
A() {
System.out.println("类 A 的构造函数。");
}
// 抽象方法
abstract void abstractMethod();
// 非抽象方法
public void nonAbstractMethod() {
System.out.println("这是抽象类 A 的非抽象方法。");
}
}
// 抽象类 B 继承抽象类 A
abstract class B extends A {
// 重写抽象方法
B() {
System.out.println("类 B 的构造函数。");
}
@Override
public void abstractMethod() {
System.out.println("抽象类 B 实现了抽象类 A 的抽象方法。");
}
public void callNonAbstractMethod() {
// 调用 自己重写的 的非抽象方法 如果自己没重写,就调用上一级父类的
nonAbstractMethod();
}
@Override
public void nonAbstractMethod() {
System.out.println("类 B 的非抽象方法。");
}
}
// 类 C 继承抽象类 B
class C extends B {
C() {
System.out.println("类 C 的构造函数。");
}
@Override
public void abstractMethod() {
System.out.println("类 C 重写了B的抽象方法(B重写A)。");
}
}
// 测试类
public class Main {
public static void main(String[] args) {
// 实例化类 C 没有显式地实例化抽象类 B
C c = new C();
System.out.println("---------");
// 调用非抽象方法 实际上调用了B(因为C没有 B才有)
c.callNonAbstractMethod();
System.out.println("---------");
// 调用重写的抽象方法 C有,就调用C的了 如果C没有就调用B的
c.abstractMethod();
}
}
在 Java 中,当子类重写了父类的方法后,如果通过子类的实例调用该方法,默认执行的是子类重写后的版本,而不是父类的版本。这是方法重写(Override)的核心特性之一,称为运行时多态(Runtime Polymorphism)或动态绑定(Dynamic Binding)。
以下是关键点:
- 子类对象优先执行子类的方法:当子类重写了父类的方法,调用方法时会优先执行子类的版本。
- 通过父类引用调用子类对象:即使用父类的引用指向子类对象,调用的方法仍然是子类重写后的版本。
注意事项1
- 如果方法在父类中是
final
或static
,子类不能重写,调用时将直接执行父类的版本。 - 构造方法不能被重写,但可以通过继承实现相关逻辑。
注意事项2
- 抽象类的特性:
- 抽象类可以有构造函数,但不能直接实例化。
- 抽象方法必须在子类中实现,除非子类也是抽象类。(看我的示例,A作为抽象基类,不能实现抽象方法)
- 抽象方法:
- 只能声明,不能有方法体。
- 子类必须实现所有未实现的抽象方法。
- 非抽象方法:
- 抽象类中可以包含普通方法(非抽象方法),这些方法可以直接在抽象类或子类中调用。
接口:
关键点
-
抽象类的必要性:
- 如果类
B
没有实现接口A
的所有抽象方法,就必须声明为abstract
。 - 抽象类不能直接实例化,但可以用来组织和实现部分逻辑。
- 如果类
-
实现类的职责:
- 类
C
必须实现method2
,因为B
没有实现它。(理解就行)
- 类
-
接口的契约:
- 接口是一个契约,表示实现类必须提供方法的具体实现,除非这个实现类也是抽象类。
/**
* 功能:
* 作者:IT伟
* 日期:2025/1/13 19:20
*/
// 接口 A
interface A {
// 抽象方法
void abstractMethod();
// 默认方法
default void nonAbstractMethod() {
System.out.println("这是接口 A 的默认方法。");
}
}
// 接口 B 继承接口 A
interface B extends A {
@Override
default void abstractMethod() {
System.out.println("接口 B 实现了接口 A 的抽象方法。");
}
default void callNonAbstractMethod() {
// 调用非抽象方法
nonAbstractMethod();
}
@Override
default void nonAbstractMethod() {
System.out.println("接口 B 的默认方法。");
}
}
// 类 C 实现接口 B
class C implements B {
C() {
System.out.println("类 C 的构造函数。");
}
@Override
public void abstractMethod() {
System.out.println("类 C 重写了接口 B 的抽象方法。");
}
}
// 测试类
public class Main {
public static void main(String[] args) {
// 实例化类 C
C c = new C();
System.out.println("---------");
// 调用非抽象方法 实际上调用了接口 B(因为接口 C 没有实现,使用了接口 B 的默认方法)
c.callNonAbstractMethod();
System.out.println("---------");
// 调用重写的抽象方法 C 有,就调用 C 的;如果 C 没有,就调用 B 的默认实现
c.abstractMethod();
}
}
拓展:反射调用方法
通过反射动态获取抽象类实现,调用实现类中方法,JAVA通过反射动态获取接口所有实现类并实例化,Spring用map接收注入实现类_java 调用抽象类的实例方法-CSDN博客