定义方式区别
- 成员变量:
- 抽象类:可以拥有各种访问修饰符(private、default、protected、public)的成员变量,既可以是常量,也可以是变量。例如:
abstract class AbstractClass {
private int privateVar;
protected final String CONSTANT = "常量";
public int publicVar;
}
- 接口:成员变量默认是
public static final
修饰的,即只能是常量。例如:
interface MyInterface {
int VALUE = 10; // 实际等同于public static final int VALUE = 10;
}
- 方法:
- 抽象类:可以包含抽象方法和具体方法。抽象方法只有声明,没有实现;具体方法有方法体。例如:
abstract class AbstractClass {
// 抽象方法
public abstract void abstractMethod();
// 具体方法
public void concreteMethod() {
System.out.println("这是一个具体方法");
}
}
- 接口:在Java 8之前,接口中的方法全部是抽象的(默认
public abstract
修饰),没有方法体。从Java 8开始,接口可以有默认方法(使用default
关键字修饰,有方法体)和静态方法(使用static
关键字修饰,有方法体)。例如:
interface MyInterface {
void abstractMethod(); // 实际等同于public abstract void abstractMethod();
default void defaultMethod() {
System.out.println("这是一个默认方法");
}
static void staticMethod() {
System.out.println("这是一个静态方法");
}
}
- 构造函数:
- 抽象类:可以有构造函数,虽然不能直接实例化,但构造函数可用于为子类提供初始化逻辑。例如:
abstract class AbstractClass {
private int value;
AbstractClass(int value) {
this.value = value;
}
}
- 接口:不能有构造函数,因为接口不是用来实例化的,而是被类实现。
使用场景区别
- 抽象类:
- 场景一:提取公共代码:当多个类有一些共同的属性和方法实现时,可以将这些共性提取到抽象类中。例如,
Animal
抽象类包含name
属性和eat()
具体方法,Dog
和Cat
类继承自Animal
类,这样可以复用代码。
abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + "正在吃东西");
}
public abstract void makeSound();
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}
- 场景二:定义不完整的行为:如果某些行为在抽象类中无法完全确定具体实现,可将其定义为抽象方法,由子类去实现。如上述
Animal
类中的makeSound()
方法。
- 接口:
- 场景一:实现多态和功能扩展:当一个类需要实现多个不同类型的行为时,可通过实现多个接口来达成。例如,一个
Car
类既可以实现Driveable
接口表示可驾驶,又可以实现Serializable
接口表示可序列化。
interface Driveable {
void drive();
}
interface Serializable {
// 接口中通常定义方法签名,这里省略具体方法
}
class Car implements Driveable, Serializable {
@Override
public void drive() {
System.out.println("汽车在行驶");
}
}
- 场景二:定义规范和契约:接口定义了一组方法的签名,实现接口的类必须按照接口定义的规范来实现这些方法。例如,在一个电商系统中,
Payment
接口定义了支付相关的方法,AlipayPayment
和WechatPayment
类实现该接口,保证了支付功能的一致性和规范性。
interface Payment {
void pay(double amount);
}
class AlipayPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付" + amount + "元");
}
}
class WechatPayment implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用微信支付" + amount + "元");
}
}