第 9 章 / 共 20 章
抽象类与接口
abstract、interface、default 方法、函数式接口家族
抽象类(abstract class)
用 abstract 修饰的类不能直接实例化,必须被继承。常用于"已经有部分实现、剩余细节交给子类"的场景。抽象类可以有字段、构造器、普通方法、抽象方法。
// AbstractDemo.java
public class AbstractDemo {
public static void main(String[] args) {
Shape s = new Circle(2);
s.describe();
}
}
abstract class Shape {
abstract double area(); // 抽象方法:只声明不实现
void describe() { // 普通方法
System.out.println("area = " + area());
}
}
class Circle extends Shape {
double r;
Circle(double r) { this.r = r; }
@Override double area() { return Math.PI * r * r; }
}接口(interface)
接口定义"能做什么",不关心"怎么做"。类用 implements 声明实现某个接口;接口里默认所有方法 public abstract、所有字段 public static final,可以省略写。
// InterfaceDemo.java
public class InterfaceDemo {
public static void main(String[] args) {
Greeter g = new EnglishGreeter();
g.greet("Alice");
}
}
interface Greeter {
void greet(String name); // 隐含 public abstract
}
class EnglishGreeter implements Greeter {
@Override
public void greet(String name) {
System.out.println("Hello, " + name);
}
}实现多个接口
类只能 extends 一个父类,但可以 implements 任意多个接口。这是 Java 实现"多继承"能力的方式(继承行为合约,不继承实现)。
// MultiInterface.java
public class MultiInterface {
public static void main(String[] args) {
Robot r = new Robot();
r.run();
r.compute();
}
}
interface Runnable2 { void run(); }
interface Computer { void compute(); }
class Robot implements Runnable2, Computer {
@Override public void run() { System.out.println("running"); }
@Override public void compute() { System.out.println("computing"); }
}default 方法(Java 8+)
default 方法在接口里提供"默认实现",实现类可以不覆盖直接用。这让接口能加新方法而不破坏老的实现类——Java 8 的 Collection 接口正是借此加了 stream() 等方法。
// DefaultMethod.java
public class DefaultMethod {
public static void main(String[] args) {
Logger log = new ConsoleLogger();
log.info("hello");
log.error("boom");
}
}
interface Logger {
void log(String level, String msg);
default void info(String msg) { log("INFO", msg); }
default void error(String msg) { log("ERROR", msg); }
}
class ConsoleLogger implements Logger {
@Override
public void log(String level, String msg) {
System.out.println("[" + level + "] " + msg);
}
}static 方法与常量
接口也能定义 static 方法(属于接口本身,通过 接口名.方法 调用)和 static final 常量。Comparator.comparing 等就是接口的 static 工厂方法。
// InterfaceStatic.java
public class InterfaceStatic {
public static void main(String[] args) {
System.out.println(MathOp.PI);
System.out.println(MathOp.square(5));
}
}
interface MathOp {
double PI = 3.14159; // 隐含 public static final
static int square(int n) { // static 方法
return n * n;
}
}抽象类 vs 接口怎么选
- 抽象类:你已经有了部分实现 / 字段 / 构造逻辑,让子类只补一小部分
- 接口:你只想约定"能力",让多个无关的类都能宣称自己支持这个能力
- 需要被多个无关类型继承 → 必然是接口(因为类不能多继承)
- Java 8 default 方法之后,接口已经能像抽象类那样"带默认行为",新代码优先用接口
函数式接口与 @FunctionalInterface
只有一个抽象方法的接口叫"函数式接口",可以用 lambda 表达式 / 方法引用直接传值实现。加 @FunctionalInterface 注解让编译器检查:万一不小心加了第二个抽象方法会立即报错。
// FunctionalDemo.java
public class FunctionalDemo {
public static void main(String[] args) {
Calculator add = (a, b) -> a + b; // lambda
Calculator mul = (a, b) -> a * b;
System.out.println(add.apply(2, 3)); // 5
System.out.println(mul.apply(2, 3)); // 6
}
}
@FunctionalInterface
interface Calculator {
int apply(int a, int b);
// int apply2(int a); // 加这行就编译报错:不是函数式接口
}标准函数式接口家族(java.util.function)
标准库内置了一组通用函数式接口,覆盖绝大多数需求,不必每次都自己定义。Stream API、Optional 等都是基于这些接口。
Function<T, R> T -> R (映射,最常用)
BiFunction<T, U, R> (T, U) -> R (二元映射)
Predicate<T> T -> boolean (判断)
Consumer<T> T -> void (消费)
Supplier<T> () -> T (供给)
UnaryOperator<T> T -> T (同类型映射,Function 的特化)
BinaryOperator<T> (T, T) -> T (归约用)// StdFunctional.java
import java.util.function.*;
public class StdFunctional {
public static void main(String[] args) {
Function<Integer, String> toHex = i -> Integer.toHexString(i);
System.out.println(toHex.apply(255)); // ff
Predicate<String> nonEmpty = s -> s != null && !s.isBlank();
System.out.println(nonEmpty.test("")); // false
System.out.println(nonEmpty.test("hi")); // true
Consumer<String> print = System.out::println;
print.accept("hello");
Supplier<Long> now = System::currentTimeMillis;
System.out.println(now.get());
BinaryOperator<Integer> sum = Integer::sum;
System.out.println(sum.apply(2, 3)); // 5
}
}