抽象类和接口
抽象类(abstract)
- 抽象类用于 提取共性、定义规范,是面向对象编程中非常重要的概念。
 - 当分析事物时,发现多个类有 共性方法,但具体实现不同,可以把方法声明提取到父类中,而不提供实现,这个方法就称为抽象方法。
 - 抽象方法:只有方法声明,没有方法体,用
 abstract修饰。- 抽象类:包含抽象方法的类,必须用
 abstract修饰。
抽象类的特点
- 定义:用
 abstract修饰的类称为抽象类。- 实例化:抽象类不能直接实例化,因为抽象方法只有声明,没有具体实现。
 - 成员变量:可以定义普通成员变量和静态变量。
 - 构造方法:抽象类可以有构造方法,方便子类创建对象时初始化抽象类的属性。
 - 方法类型:可以定义普通方法,也可以定义抽象方法;即使没有抽象方法,也可以是抽象类。
 - 继承关系:抽象类通常作为父类,子类必须重写父类的抽象方法,才能实例化使用。
 
抽象方法的特点
- 定义:用
 abstract修饰的方法称为抽象方法。- 方法体:抽象方法只有声明,没有方法体。
 - 子类约束:子类必须实现父类的抽象方法,或者子类也声明为抽象类,否则编译失败。
 - 类限制:抽象方法只能存在于抽象类或接口中,不能存在于普通类中。
 - 关键字限制:
 abstract不能与private、final、static共存:
private:方法不能被继承,也无法重写。final/static:方法可以被继承,但无法重写。
public class Main { public static void main(String[] args) { // Animal a = new Animal("Animal"); // 编译错误,抽象类不能实例化 Animal dog = new Dog("Buddy"); dog.sound(); // 输出: Buddy barks dog.eat(); // 输出: Buddy is eating } } abstract class Animal { String name; // 构造方法 Animal(String name) { this.name = name; } // 抽象方法 abstract void sound(); // 普通方法 void eat() { System.out.println(name + " is eating"); } } class Dog extends Animal { Dog(String name) { super(name); } @Override void sound() { System.out.println(name + " barks"); } }
接口(interface)
- 接口是完全面向规范的抽象类型,用于定义类必须实现的公共方法规范。
 - 当一个抽象类中的方法全部是抽象方法时,可以用接口来表示。
 - 抽象类可以包含部分具体方法,而接口不提供任何实现(JDK8+ 支持 default / static 方法除外)。
 - 接口使用
 interface关键字定义,编译后生成.class文件。- 接口不能实例化,实现接口的类必须提供方法具体实现。
 - 接口支持多继承(使用
 extends实现多个接口的继承)。
接口的组成
属性:接口中定义的属性都是全局静态常量,默认由
public static final修饰。interface Config { int MAX = 100; // 相当于 public static final int MAX = 100; }方法:
- JDK 1.8 之前:接口中只能定义抽象方法,默认
 public abstract- JDK 1.8+:可以定义
 default方法和静态方法- JDK 9+:支持私有方法
 - 接口中不能有构造方法,因为没有实例变量需要初始化。
 public class Main { public static void main(String[] args) { Example obj = new ExampleImpl(); obj.abstractMethod(); // 调用抽象方法的实现 obj.defaultMethod(); // 调用默认方法(内部会调用私有方法) Example.staticMethod(); // 调用静态方法 } } interface Example { void abstractMethod(); // 抽象方法 default void defaultMethod() { // 默认方法 privateMethod(); // 在接口内部调用私有方法 System.out.println("default method"); } static void staticMethod() { // 静态方法 System.out.println("static method"); } private void privateMethod() { // 私有方法(JDK9+) System.out.println("private method"); } } class ExampleImpl implements Example { @Override public void abstractMethod() { System.out.println("abstract method implemented"); } }
接口的实现
- 类与接口关系:
 
- 类与类:继承 →
 extends- 类与接口:实现 →
 implements- 抽象方法实现:
 
- 实现接口的类必须重写接口中的抽象方法,完成具体逻辑
 - 如果实现了接口的全部抽象方法 → 类可以实例化
 - 如果只实现部分方法 → 类必须声明为抽象类,不能实例化
 - 多接口实现:
 
- 一个类可以实现多个接口,实现多继承效果
 - 避免了类的多重继承带来的复杂性
 public class Main { public static void main(String[] args) { Duck d = new Duck(); d.fly(); // 输出: Duck is flying d.swim(); // 输出: Duck is swimming d.land(); // 输出: Landing... } } interface Flyable { void fly(); // 抽象方法 default void land() { // 默认方法 System.out.println("Landing..."); } } interface Swimmable { void swim(); } class Duck implements Flyable, Swimmable { @Override public void fly() { System.out.println("Duck is flying"); } @Override public void swim() { System.out.println("Duck is swimming"); } }
接口和抽象类的区别
接口和抽象类都是面向抽象的设计手段,但侧重点不同:
- 接口(interface):对动作或行为的抽象,强调规范和能力。
 - 抽象类(abstract class):对事物共性或根源的抽象,强调结构和基本特性。
 抽象级别(从高到低):
接口 > 抽象类 > 普通类相同点
- 都是向上抽取而来的概念,不能被实例化。
 - 都可以包含抽象方法,但不提供具体实现。
 不同点
- 继承关系
 
- 抽象类需要被继承(
 extends),且只能单继承。- 接口需要被实现(
 implements),且可以实现多个接口。- 成员变量
 
- 抽象类中可以定义普通成员变量和静态变量。
 - 接口中的变量都是全局静态常量(默认
 public static final)。- 构造方法
 
- 抽象类可以有构造方法,方便子类初始化属性。
 - 接口不能有构造方法,因为接口没有需要初始化的成员变量。
 - 方法类型
 
- 抽象类可以定义抽象方法和普通方法。
 - 接口(JDK1.8以前)只能定义抽象方法;JDK1.8以后可以定义
 default方法和静态方法;JDK1.9之后支持私有方法。- 语义关系
 
- 抽象类描述的是 “is a”,体现体系共性内容。
 - 接口描述的是 “is like a”,体现额外行为或能力。
 
继承和实现的冲突
当一个类继承父类并实现一个或多个接口时,可能会遇到方法和变量冲突。
方法冲突
- 方法签名冲突
 
- 父类和接口中定义了相同方法签名(名称 + 参数列表),不会产生冲突,子类会直接继承父类的方法实现。
 - 默认方法冲突
 
- JDK8+ 接口可以定义默认方法(
 default)。- 如果父类和接口都有相同签名的方法,父类方法优先。
 - 如果实现了多个接口且接口之间有相同默认方法,子类必须显式重写方法,否则编译器报错。
 public class Main { public static void main(String[] args) { Child c = new Child(); c.show(); // 输出: Parent show } } interface A { default void show() { System.out.println("A show"); } } interface B { default void show() { System.out.println("B show"); } } class Parent { void show() { System.out.println("Parent show"); } } class Child extends Parent implements A, B { @Override public void show() { super.show(); // 调用父类方法 } }
变量冲突
接口间字段冲突
- 实现多个接口且接口中有同名静态字段时,必须通过接口名指定使用。
 class Z implements X, Y { void print() { System.out.println(X.VALUE); // 访问 X 接口中的 VALUE System.out.println(Y.VALUE); // 访问 Y 接口中的 VALUE } public static void main(String[] args) { Z z = new Z(); z.print(); } } interface X { int VALUE = 1; } interface Y { int VALUE = 2; }父类与接口字段冲突
- 父类和接口有同名字段时,子类需要明确指定使用哪个字段。
 class Child extends Parent implements I { void print() { System.out.println(super.num); // 访问父类字段 System.out.println(I.num); // 访问接口字段 } public static void main(String[] args) { Child c = new Child(); c.print(); } } class Parent { int num = 10; } interface I { int num = 20; }