面向对象编程(OOP)
封装、继承和多态:Java 的三大面向对象编程(OOP)特性
Java 是一种面向对象编程语言(区别于面向对象or面向过程),面向对象编程(OOP)通过将数据和方法封装在对象中,旨在提高程序的可维护性、可扩展性和复用性。OOP 主要包括以下三大核心特性:封装、继承、多态。
一、封装(Encapsulation)
1.1 封装的核心概念
/**
* 封装:将数据和操作数据的方法绑定在一起,隐藏内部实现细节
* 核心原则:高内聚、低耦合
*/
public class BankAccount {
// ========== 1. 数据隐藏(私有字段) ==========
private String accountNumber;
private String ownerName;
private double balance;
private List<Transaction> transactions;
// ========== 2. 构造器(初始化对象) ==========
public BankAccount(String accountNumber, String ownerName) {
this.accountNumber = accountNumber;
this.ownerName = ownerName;
this.balance = 0.0;
this.transactions = new ArrayList<>();
}
// ========== 3. 公共接口(受控访问) ==========
// Getter:只读访问
public String getAccountNumber() {
return accountNumber;
}
public String getOwnerName() {
return ownerName;
}
// 只提供余额查询,不提供直接修改
public double getBalance() {
return balance;
}
// Setter:带验证的写入
public void setOwnerName(String ownerName) {
if (ownerName == null || ownerName.trim().isEmpty()) {
throw new IllegalArgumentException("Owner name cannot be empty");
}
this.ownerName = ownerName;
}
// ========== 4. 业务方法(封装业务逻辑) ==========
/**
* 存款
* ✅ 优点:
* - 参数验证
* - 业务规则集中管理
* - 记录交易历史
*/
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Deposit amount must be positive");
}
balance += amount;
transactions.add(new Transaction("DEPOSIT", amount, balance));
logTransaction("Deposited: " + amount);
}
/**
* 取款
* ✅ 封装了复杂的业务逻辑
*/
public boolean withdraw(double amount) {
// 验证 1:金额有效性
if (amount <= 0) {
throw new IllegalArgumentException("Withdrawal amount must be positive");
}
// 验证 2:余额充足性
if (amount > balance) {
System.out.println("Insufficient balance");
return false;
}
// 验证 3:单次取款限额
if (amount > 10000) {
System.out.println("Single withdrawal limit exceeded");
return false;
}
balance -= amount;
transactions.add(new Transaction("WITHDRAW", amount, balance));
logTransaction("Withdrew: " + amount);
return true;
}
/**
* 转账
* ✅ 封装了跨账户操作的复杂性
*/
public boolean transfer(BankAccount target, double amount) {
if (target == null) {
throw new IllegalArgumentException("Target account cannot be null");
}
if (this.withdraw(amount)) {
target.deposit(amount);
logTransaction("Transferred " + amount + " to " + target.getAccountNumber());
return true;
}
return false;
}
// ========== 5. 内部辅助方法(私有) ==========
private void logTransaction(String message) {
System.out.println("[" + LocalDateTime.now() + "] " + message);
}
// ========== 6. 不可变视图(防御性拷贝) ==========
public List<Transaction> getTransactions() {
// ❌ 错误:直接返回内部集合
// return transactions;
// ✅ 正确:返回不可变副本
return Collections.unmodifiableList(new ArrayList<>(transactions));
}
/**
* 交易记录(不可变类)
*/
public static class Transaction {
private final String type;
private final double amount;
private final double balanceAfter;
private final LocalDateTime timestamp;
public Transaction(String type, double amount, double balanceAfter) {
this.type = type;
this.amount = amount;
this.balanceAfter = balanceAfter;
this.timestamp = LocalDateTime.now();
}
// 只提供 getter,无 setter(不可变)
public String getType() { return type; }
public double getAmount() { return amount; }
public double getBalanceAfter() { return balanceAfter; }
public LocalDateTime getTimestamp() { return timestamp; }
}
}
1.2 访问控制修饰符
/**
* Java 四种访问级别
*/
public class AccessControlDemo {
// ========== 1. private(类内部) ==========
private String privateField = "private";
private void privateMethod() {
System.out.println("Only accessible within this class");
}
// ========== 2. default(包级别) ==========
String defaultField = "default"; // 无修饰符
void defaultMethod() {
System.out.println("Accessible within the same package");
}
// ========== 3. protected(包 + 子类) ==========
protected String protectedField = "protected";
protected void protectedMethod() {
System.out.println("Accessible within package and subclasses");
}
// ========== 4. public(所有地方) ==========
public String publicField = "public";
public void publicMethod() {
System.out.println("Accessible everywhere");
}
/**
* 访问级别表格:
*
* ┌──────────┬────────┬──────┬────────┬──────────┐
* │ 修饰符 │ 同类 │ 同包 │ 子类 │ 其他包 │
* ├──────────┼────────┼──────┼────────┼──────────┤
* │ private │ ✅ │ ❌ │ ❌ │ ❌ │
* │ default │ ✅ │ ✅ │ ❌ │ ❌ │
* │protected │ ✅ │ ✅ │ ✅ │ ❌ │
* │ public │ ✅ │ ✅ │ ✅ │ ✅ │
* └──────────┴────────┴──────┴────────┴──────────┘
*/
}
// ========== 同包类测试 ==========
class SamePackageTest {
public void test() {
AccessControlDemo demo = new AccessControlDemo();
// demo.privateField; // ❌ 编译错误
// demo.privateMethod(); // ❌ 编译错误
String s1 = demo.defaultField; // ✅
demo.defaultMethod(); // ✅
String s2 = demo.protectedField; // ✅
demo.protectedMethod(); // ✅
String s3 = demo.publicField; // ✅
demo.publicMethod(); // ✅
}
}
// ========== 不同包子类测试 ==========
package com.other;
class SubclassTest extends AccessControlDemo {
public void test() {
// privateField; // ❌ 编译错误
// defaultField; // ❌ 编译错误(不同包)
String s1 = protectedField; // ✅
protectedMethod(); // ✅
String s2 = publicField; // ✅
publicMethod(); // ✅
}
}
1.3 封装的最佳实践
/**
* 封装的设计原则
*/
public class EncapsulationBestPractices {
// ========== 1. 最小化可变性 ==========
// ❌ 错误:可变字段
public List<String> items = new ArrayList<>();
// ✅ 正确:不可变字段
private final List<String> items2 = new ArrayList<>();
public List<String> getItems() {
return Collections.unmodifiableList(items2);
}
public void addItem(String item) {
items2.add(item);
}
// ========== 2. 防御性拷贝 ==========
private Date birthDate;
// ❌ 错误:返回内部可变对象的引用
public Date getBirthDate() {
return birthDate;
}
// ✅ 正确:返回副本
public Date getBirthDateSafe() {
return birthDate == null ? null : new Date(birthDate.getTime());
}
// ✅ 更好:使用不可变类型
private final LocalDate birthDate2 = LocalDate.now();
public LocalDate getBirthDate2() {
return birthDate2; // LocalDate 不可变,安全返回
}
// ========== 3. JavaBeans 规范 ==========
private String name;
// 标准 getter/setter 命名
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// boolean 类型特殊命名
private boolean active;
public boolean isActive() { // 使用 is 前缀
return active;
}
public void setActive(boolean active) {
this.active = active;
}
// ========== 4. Lombok 简化(可选) ==========
/**
* 使用 Lombok 注解自动生成代码
*/
@Data // 生成 getter/setter/toString/equals/hashCode
@Builder // 生成建造者模式
@AllArgsConstructor
@NoArgsConstructor
public static class User {
private Long id;
private String username;
private String email;
@Setter(AccessLevel.NONE) // 不生成 setter
private LocalDateTime createdAt;
}
// 使用示例
User user = User.builder()
.id(1L)
.username("admin")
.email("admin@example.com")
.build();
}
二、继承(Inheritance)
2.1 继承的基础
/**
* 继承:子类继承父类的属性和方法
* 关键词:extends
*/
// ========== 父类(基类、超类) ==========
public class Animal {
// 父类字段
protected String name;
protected int age;
private String species; // private 字段子类不可直接访问
// 父类构造器
public Animal(String name, int age, String species) {
this.name = name;
this.age = age;
this.species = species;
}
// 父类方法
public void eat() {
System.out.println(name + " is eating");
}
public void sleep() {
System.out.println(name + " is sleeping");
}
// final 方法:子类不能重写
public final void breathe() {
System.out.println(name + " is breathing");
}
// protected 方法:子类可访问
protected void makeSound() {
System.out.println("Some generic sound");
}
// Getter
public String getSpecies() {
return species;
}
}
// ========== 子类(派生类) ==========
public class Dog extends Animal {
// 子类独有字段
private String breed;
// 子类构造器:必须调用父类构造器
public Dog(String name, int age, String breed) {
super(name, age, "Canine"); // ✅ super() 调用父类构造器
this.breed = breed;
}
// ========== 方法重写(Override) ==========
/**
* @Override 注解:
* - 编译期检查是否正确重写
* - 提高代码可读性
*/
@Override
public void eat() {
System.out.println(name + " is eating dog food");
}
@Override
protected void makeSound() {
System.out.println(name + " barks: Woof! Woof!");
}
// ❌ 编译错误:不能重写 final 方法
// @Override
// public void breathe() {}
// ========== 子类独有方法 ==========
public void fetch() {
System.out.println(name + " is fetching the ball");
}
public void wagTail() {
System.out.println(name + " is wagging tail");
}
// ========== 访问父类成员 ==========
public void showInfo() {
// 访问 protected 字段
System.out.println("Name: " + name); // ✅
System.out.println("Age: " + age); // ✅
// 访问 private 字段:需要通过 getter
System.out.println("Species: " + getSpecies()); // ✅
// 调用父类方法
super.eat(); // 显式调用父类版本
this.eat(); // 调用子类重写版本
}
}
// ========== 使用示例 ==========
public class InheritanceDemo {
public static void main(String[] args) {
Dog dog = new Dog("Buddy", 3, "Golden Retriever");
// 调用继承的方法
dog.sleep(); // 来自 Animal
dog.breathe(); // 来自 Animal(final)
// 调用重写的方法
dog.eat(); // 来自 Dog(重写)
dog.makeSound(); // 来自 Dog(重写)
// 调用子类独有方法
dog.fetch(); // 来自 Dog
dog.wagTail(); // 来自 Dog
dog.showInfo();
}
}
2.2 super 关键字详解
/**
* super 关键字的三种用法
*/
public class SuperKeywordDemo {
// ========== 父类 ==========
static class Parent {
protected String name = "Parent";
public Parent() {
System.out.println("Parent constructor");
}
public Parent(String name) {
this.name = name;
System.out.println("Parent constructor with name: " + name);
}
public void display() {
System.out.println("Parent display");
}
public void print() {
System.out.println("Parent print");
}
}
// ========== 子类 ==========
static class Child extends Parent {
private String name = "Child";
public Child() {
// super() 必须是构造器的第一条语句
super("ParentName"); // ✅ 用法 1:调用父类构造器
System.out.println("Child constructor");
}
@Override
public void display() {
// ✅ 用法 2:访问父类字段
System.out.println("Parent name: " + super.name);
System.out.println("Child name: " + this.name);
}
@Override
public void print() {
// ✅ 用法 3:调用父类方法
super.print(); // 调用父类版本
System.out.println("Child print");
}
public void showAll() {
super.display(); // 调用父类 display()
this.display(); // 调用子类 display()
}
}
public static void main(String[] args) {
Child child = new Child();
/**
* 输出:
* Parent constructor with name: ParentName
* Child constructor
*/
child.display();
/**
* 输出:
* Parent name: Parent
* Child name: Child
*/
child.print();
/**
* 输出:
* Parent print
* Child print
*/
}
/**
* super vs this:
*
* super:
* - 访问父类成员
* - 调用父类构造器
* - 必须是构造器第一条语句
*
* this:
* - 访问当前类成员
* - 调用当前类其他构造器
* - 必须是构造器第一条语句
*
* ⚠️ super() 和 this() 不能同时出现!
*/
}
2.3 构造器链
/**
* 构造器链:子类构造器自动调用父类构造器
*/
public class ConstructorChainDemo {
// ========== 三层继承关系 ==========
static class GrandParent {
public GrandParent() {
System.out.println("1. GrandParent()");
}
}
static class Parent extends GrandParent {
public Parent() {
super(); // 隐式调用(可省略)
System.out.println("2. Parent()");
}
}
static class Child extends Parent {
public Child() {
super(); // 隐式调用(可省略)
System.out.println("3. Child()");
}
}
public static void main(String[] args) {
new Child();
/**
* 输出:
* 1. GrandParent()
* 2. Parent()
* 3. Child()
*
* 执行顺序:从顶层到底层
*/
}
// ========== 构造器重载 + 链式调用 ==========
static class Person {
private String name;
private int age;
private String address;
// 主构造器
public Person(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
System.out.println("Full constructor");
}
// 委托构造器
public Person(String name, int age) {
this(name, age, "Unknown"); // 调用主构造器
System.out.println("Two-arg constructor");
}
public Person(String name) {
this(name, 0); // 调用两参数构造器
System.out.println("One-arg constructor");
}
public Person() {
this("Unknown"); // 调用单参数构造器
System.out.println("No-arg constructor");
}
}
static class Employee extends Person {
private String company;
public Employee(String name, int age, String address, String company) {
super(name, age, address); // 必须先调用父类构造器
this.company = company;
System.out.println("Employee constructor");
}
}
public static void test() {
new Employee("Alice", 30, "NYC", "Google");
/**
* 输出:
* Full constructor
* Employee constructor
*/
}
/**
* 构造器调用规则:
*
* 1️⃣ 如果子类构造器没有显式调用 super(),编译器自动插入 super()
* 2️⃣ 如果父类没有无参构造器,子类必须显式调用父类有参构造器
* 3️⃣ super() 或 this() 必须是构造器的第一条语句
* 4️⃣ super() 和 this() 不能同时出现
*/
}
2.4 继承与初始化顺序
/**
* 完整的初始化顺序
*/
public class InitializationOrderDemo {
static class Parent {
// 1. 父类静态字段
private static String staticField = initStaticField();
// 2. 父类静态块
static {
System.out.println("2. Parent static block");
}
// 3. 父类实例字段
private String instanceField = initInstanceField();
// 4. 父类实例块
{
System.out.println("4. Parent instance block");
}
// 5. 父类构造器
public Parent() {
System.out.println("5. Parent constructor");
}
private static String initStaticField() {
System.out.println("1. Parent static field");
return "parent static";
}
private String initInstanceField() {
System.out.println("3. Parent instance field");
return "parent instance";
}
}
static class Child extends Parent {
// 6. 子类静态字段
private static String staticField = initStaticField();
// 7. 子类静态块
static {
System.out.println("7. Child static block");
}
// 8. 子类实例字段
private String instanceField = initInstanceField();
// 9. 子类实例块
{
System.out.println("9. Child instance block");
}
// 10. 子类构造器
public Child() {
super();
System.out.println("10. Child constructor");
}
private static String initStaticField() {
System.out.println("6. Child static field");
return "child static";
}
private String initInstanceField() {
System.out.println("8. Child instance field");
return "child instance";
}
}
public static void main(String[] args) {
System.out.println("=== First instantiation ===");
new Child();
System.out.println("\n=== Second instantiation ===");
new Child();
/**
* 输出:
* === First instantiation ===
* 1. Parent static field
* 2. Parent static block
* 6. Child static field
* 7. Child static block
* 3. Parent instance field
* 4. Parent instance block
* 5. Parent constructor
* 8. Child instance field
* 9. Child instance block
* 10. Child constructor
*
* === Second instantiation ===
* 3. Parent instance field
* 4. Parent instance block
* 5. Parent constructor
* 8. Child instance field
* 9. Child instance block
* 10. Child constructor
*
* ⚠️ 静态内容只初始化一次!
*/
}
/**
* 初始化顺序总结:
*
* 1️⃣ 父类静态成员(字段 + 块)
* 2️⃣ 子类静态成员(字段 + 块)
* 3️⃣ 父类实例成员(字段 + 块)
* 4️⃣ 父类构造器
* 5️⃣ 子类实例成员(字段 + 块)
* 6️⃣ 子类构造器
*/
}
2.5 方法重写(Override)详解
/**
* 方法重写的规则和最佳实践
*/
public class OverrideDemo {
static class Parent {
// 返回类型:Object
public Object getValue() {
return "Parent";
}
// 访问修饰符:protected
protected void display() {
System.out.println("Parent display");
}
// 抛出异常:IOException
public void process() throws IOException {
System.out.println("Parent process");
}
// final 方法:不能重写
public final void finalMethod() {
System.out.println("Final method");
}
// static 方法:不能重写(可以隐藏)
public static void staticMethod() {
System.out.println("Parent static");
}
}
static class Child extends Parent {
// ========== 规则 1:协变返回类型 ==========
@Override
public String getValue() { // String 是 Object 的子类 ✅
return "Child";
}
// ========== 规则 2:访问权限不能更严格 ==========
@Override
public void display() { // protected -> public ✅
System.out.println("Child display");
}
// ❌ 编译错误:不能从 protected 降为 private
// @Override
// private void display() {}
// ========== 规则 3:异常限制 ==========
@Override
public void process() throws FileNotFoundException { // IOException 的子类 ✅
System.out.println("Child process");
}
// ❌ 编译错误:不能抛出更宽泛的异常
// @Override
// public void process() throws Exception {}
// ========== 规则 4:不能重写 final 方法 ==========
// ❌ 编译错误
// @Override
// public void finalMethod() {}
// ========== 规则 5:static 方法不是重写,是隐藏 ==========
public static void staticMethod() { // 不是 @Override
System.out.println("Child static");
}
}
public static void main(String[] args) {
// ========== 多态调用 ==========
Parent p = new Child();
Object obj = p.getValue(); // 运行时调用 Child.getValue()
System.out.println(obj); // 输出:Child
p.display(); // 运行时调用 Child.display()
// ========== 静态方法调用(编译时绑定) ==========
p.staticMethod(); // 输出:Parent static(不是多态!)
Child.staticMethod(); // 输出:Child static
/**
* 重写 vs 隐藏:
*
* 重写(Override):
* - 实例方法
* - 运行时多态(动态绑定)
* - 使用 @Override 注解
*
* 隐藏(Hiding):
* - 静态方法、静态字段
* - 编译时绑定
* - 无 @Override 注解
*/
}
}
三、多态(Polymorphism)
3.1 多态的基本概念
/**
* 多态:同一个引用类型,指向不同的对象时,调用同一个方法表现出不同的行为
*
* 多态的三个必要条件:
* 1️⃣ 继承(或实现接口)
* 2️⃣ 重写(子类重写父类方法)
* 3️⃣ 向上转型(父类引用指向子类对象)
*/
public class PolymorphismBasics {
// ========== 父类 ==========
static class Animal {
public void makeSound() {
System.out.println("Some generic sound");
}
public void eat() {
System.out.println("Animal is eating");
}
}
// ========== 子类 1 ==========
static class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof! Woof!");
}
@Override
public void eat() {
System.out.println("Dog is eating bones");
}
// 子类独有方法
public void fetch() {
System.out.println("Dog is fetching");
}
}
// ========== 子类 2 ==========
static class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow! Meow!");
}
@Override
public void eat() {
System.out.println("Cat is eating fish");
}
// 子类独有方法
public void climb() {
System.out.println("Cat is climbing");
}
}
// ========== 子类 3 ==========
static class Bird extends Animal {
@Override
public void makeSound() {
System.out.println("Chirp! Chirp!");
}
@Override
public void eat() {
System.out.println("Bird is eating seeds");
}
// 子类独有方法
public void fly() {
System.out.println("Bird is flying");
}
}
// ========== 多态演示 ==========
public static void main(String[] args) {
// ========== 1. 向上转型(Upcasting) ==========
Animal animal1 = new Dog(); // ✅ 自动转型
Animal animal2 = new Cat(); // ✅ 自动转型
Animal animal3 = new Bird(); // ✅ 自动转型
// 多态调用:运行时根据实际对象类型调用对应方法
animal1.makeSound(); // 输出:Woof! Woof!
animal2.makeSound(); // 输出:Meow! Meow!
animal3.makeSound(); // 输出:Chirp! Chirp!
animal1.eat(); // 输出:Dog is eating bones
animal2.eat(); // 输出:Cat is eating fish
animal3.eat(); // 输出:Bird is eating seeds
// ❌ 不能调用子类独有方法
// animal1.fetch(); // 编译错误
// animal2.climb(); // 编译错误
// animal3.fly(); // 编译错误
// ========== 2. 向下转型(Downcasting) ==========
// ✅ 正确的向下转型
if (animal1 instanceof Dog) {
Dog dog = (Dog) animal1;
dog.fetch(); // 现在可以调用子类方法
}
// ❌ 错误的向下转型:运行时异常
try {
Dog dog = (Dog) animal2; // animal2 实际是 Cat
dog.fetch();
} catch (ClassCastException e) {
System.out.println("ClassCastException: Cannot cast Cat to Dog");
}
// ========== 3. 数组多态 ==========
Animal[] animals = {
new Dog(),
new Cat(),
new Bird(),
new Dog(),
new Cat()
};
// 统一处理不同类型的对象
for (Animal animal : animals) {
animal.makeSound(); // 多态调用
animal.eat();
System.out.println("---");
}
// ========== 4. 集合多态 ==========
List<Animal> animalList = new ArrayList<>();
animalList.add(new Dog());
animalList.add(new Cat());
animalList.add(new Bird());
for (Animal animal : animalList) {
animal.makeSound();
}
// ========== 5. 方法参数多态 ==========
feedAnimal(new Dog());
feedAnimal(new Cat());
feedAnimal(new Bird());
}
/**
方法参数多态:接受父类类型参数,可以传入任意子类对象
*/
public static void feedAnimal(Animal animal) {
System.out.println("Feeding the animal...");
animal.eat(); // 多态调用
}
}
3.2 编译时多态(方法重载)
/**
* 编译时多态(静态多态):方法重载(Overloading)
* 特点:编译期确定调用哪个方法
*/
public class CompileTimePolymorphism {
// ========== 方法重载的四种方式 ==========
// 1️⃣ 参数个数不同
public void print(String message) {
System.out.println("String: " + message);
}
public void print(String message, int count) {
for (int i = 0; i < count; i++) {
System.out.println(message);
}
}
// 2️⃣ 参数类型不同
public void display(int value) {
System.out.println("int: " + value);
}
public void display(double value) {
System.out.println("double: " + value);
}
public void display(String value) {
System.out.println("String: " + value);
}
// 3️⃣ 参数顺序不同
public void process(String name, int age) {
System.out.println(name + " is " + age + " years old");
}
public void process(int age, String name) {
System.out.println(name + " is " + age + " years old");
}
// 4️⃣ 可变参数重载
public void sum(int... numbers) {
int total = 0;
for (int num : numbers) {
total += num;
}
System.out.println("Sum: " + total);
}
public void sum(int a, int b) {
System.out.println("Sum of two: " + (a + b));
}
// ========== 重载解析优先级 ==========
public static void main(String[] args) {
CompileTimePolymorphism demo = new CompileTimePolymorphism();
// 测试 1:精确匹配
demo.display(10); // 调用 display(int)
demo.display(10.5); // 调用 display(double)
demo.display("Hello"); // 调用 display(String)
// 测试 2:自动类型提升
byte b = 5;
demo.display(b); // byte -> int,调用 display(int)
short s = 10;
demo.display(s); // short -> int,调用 display(int)
float f = 3.14f;
demo.display(f); // float -> double,调用 display(double)
// 测试 3:装箱
Integer integer = 100;
demo.display(integer); // Integer -> int(自动拆箱),调用 display(int)
// 测试 4:可变参数
demo.sum(1, 2); // 优先调用 sum(int, int)
demo.sum(1, 2, 3); // 调用 sum(int...)
demo.sum(); // 调用 sum(int...)
}
/**
* 重载解析优先级(从高到低):
*
* 1️⃣ 精确匹配
* 2️⃣ 自动类型提升(byte->short->int->long->float->double)
* 3️⃣ 自动装箱/拆箱
* 4️⃣ 可变参数
*/
// ========== 不能重载的情况 ==========
// ❌ 返回类型不同不构成重载
// public int getValue() { return 1; }
// public double getValue() { return 1.0; } // 编译错误
// ❌ 仅访问修饰符不同不构成重载
// public void method() {}
// private void method() {} // 编译错误
// ❌ 仅抛出异常不同不构成重载
// public void doSomething() {}
// public void doSomething() throws Exception {} // 编译错误
}
3.3 运行时多态(方法重写)
/**
* 运行时多态(动态多态):方法重写(Overriding)
* 特点:运行时根据实际对象类型确定调用哪个方法
*/
public class RuntimePolymorphism {
// ========== 父类 ==========
static class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 可重写方法
public double getArea() {
return 0;
}
public void draw() {
System.out.println("Drawing a shape");
}
public void displayInfo() {
System.out.println("Color: " + color + ", Area: " + getArea());
}
}
// ========== 子类 1:Circle ==========
static class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public void draw() {
System.out.println("Drawing a circle with radius " + radius);
}
}
// ========== 子类 2:Rectangle ==========
static class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
@Override
public void draw() {
System.out.println("Drawing a rectangle " + width + "x" + height);
}
}
// ========== 子类 3:Triangle ==========
static class Triangle extends Shape {
private double base;
private double height;
public Triangle(String color, double base, double height) {
super(color);
this.base = base;
this.height = height;
}
@Override
public double getArea() {
return 0.5 * base * height;
}
@Override
public void draw() {
System.out.println("Drawing a triangle");
}
}
// ========== 运行时多态演示 ==========
public static void main(String[] args) {
// ========== 1. 基本多态调用 ==========
Shape shape1 = new Circle("Red", 5.0);
Shape shape2 = new Rectangle("Blue", 4.0, 6.0);
Shape shape3 = new Triangle("Green", 3.0, 4.0);
// 运行时确定调用哪个 getArea()
System.out.println("Circle area: " + shape1.getArea());
System.out.println("Rectangle area: " + shape2.getArea());
System.out.println("Triangle area: " + shape3.getArea());
// ========== 2. 方法链中的多态 ==========
shape1.displayInfo(); // displayInfo() 中调用 getArea(),多态!
shape2.displayInfo();
shape3.displayInfo();
/**
* displayInfo() 在父类中定义,但调用的 getArea()
* 是运行时根据实际对象类型确定的!
*/
// ========== 3. 集合中的多态 ==========
List<Shape> shapes = Arrays.asList(
new Circle("Red", 5.0),
new Rectangle("Blue", 4.0, 6.0),
new Triangle("Green", 3.0, 4.0),
new Circle("Yellow", 3.0)
);
// 统一处理不同形状
double totalArea = 0;
for (Shape shape : shapes) {
shape.draw(); // 多态调用
totalArea += shape.getArea(); // 多态调用
}
System.out.println("Total area: " + totalArea);
// ========== 4. instanceof 类型检查 ==========
for (Shape shape : shapes) {
if (shape instanceof Circle) {
System.out.println("Found a circle");
} else if (shape instanceof Rectangle) {
System.out.println("Found a rectangle");
} else if (shape instanceof Triangle) {
System.out.println("Found a triangle");
}
}
// ========== 5. 模式匹配(JDK 16+) ==========
for (Shape shape : shapes) {
if (shape instanceof Circle circle) { // 模式匹配 + 自动转型
System.out.println("Circle radius: " + circle.radius);
} else if (shape instanceof Rectangle rect) {
System.out.println("Rectangle: " + rect.width + "x" + rect.height);
}
}
}
/**
* 多态的底层实现:虚方法表(Virtual Method Table, VMT)
*
* 每个类都有一个虚方法表,存储该类的所有虚方法的地址。
*
* Shape VMT:
* ┌─────────────┬──────────────┐
* │ getArea() │ Shape.getArea│
* │ draw() │ Shape.draw │
* └─────────────┴──────────────┘
*
* Circle VMT:
* ┌─────────────┬──────────────┐
* │ getArea() │ Circle.getArea│ ⬅️ 重写
* │ draw() │ Circle.draw │ ⬅️ 重写
* └─────────────┴──────────────┘
*
* 调用流程:
* 1. 根据对象找到其类的虚方法表
* 2. 在虚方法表中查找方法地址
* 3. 调用对应地址的方法
*/
}
3.4 多态的实际应用
/**
* 多态的实际应用场景
*/
public class PolymorphismApplications {
// ========== 场景 1:支付系统 ==========
interface PaymentMethod {
boolean pay(double amount);
String getPaymentType();
}
static class CreditCardPayment implements PaymentMethod {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public boolean pay(double amount) {
System.out.println("Paying $" + amount + " with Credit Card " + cardNumber);
return true;
}
@Override
public String getPaymentType() {
return "Credit Card";
}
}
static class PayPalPayment implements PaymentMethod {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public boolean pay(double amount) {
System.out.println("Paying $" + amount + " with PayPal " + email);
return true;
}
@Override
public String getPaymentType() {
return "PayPal";
}
}
static class WeChatPayment implements PaymentMethod {
private String phoneNumber;
public WeChatPayment(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public boolean pay(double amount) {
System.out.println("Paying $" + amount + " with WeChat " + phoneNumber);
return true;
}
@Override
public String getPaymentType() {
return "WeChat Pay";
}
}
/**
* 订单类:使用多态处理不同支付方式
*/
static class Order {
private double totalAmount;
private PaymentMethod paymentMethod; // 多态字段
public Order(double totalAmount) {
this.totalAmount = totalAmount;
}
public void setPaymentMethod(PaymentMethod paymentMethod) {
this.paymentMethod = paymentMethod;
}
public void checkout() {
if (paymentMethod == null) {
System.out.println("Please select a payment method");
return;
}
System.out.println("Processing order...");
// 多态调用:运行时确定具体支付方式
if (paymentMethod.pay(totalAmount)) {
System.out.println("Payment successful via " + paymentMethod.getPaymentType());
} else {
System.out.println("Payment failed");
}
}
}
// ========== 场景 2:日志系统 ==========
interface Logger {
void log(String message);
void error(String message);
}
static class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("[CONSOLE LOG] " + message);
}
@Override
public void error(String message) {
System.err.println("[CONSOLE ERROR] " + message);
}
}
static class FileLogger implements Logger {
private String filename;
public FileLogger(String filename) {
this.filename = filename;
}
@Override
public void log(String message) {
System.out.println("[FILE LOG to " + filename + "] " + message);
}
@Override
public void error(String message) {
System.out.println("[FILE ERROR to " + filename + "] " + message);
}
}
static class DatabaseLogger implements Logger {
private String connectionString;
public DatabaseLogger(String connectionString) {
this.connectionString = connectionString;
}
@Override
public void log(String message) {
System.out.println("[DB LOG to " + connectionString + "] " + message);
}
@Override
public void error(String message) {
System.out.println("[DB ERROR to " + connectionString + "] " + message);
}
}
/**
* 应用服务:使用多态的日志记录器
*/
static class Application {
private Logger logger; // 多态字段
public Application(Logger logger) {
this.logger = logger;
}
public void start() {
logger.log("Application started");
}
public void processData() {
try {
logger.log("Processing data...");
int result = 100 / 0; // 异常
} catch (Exception e) {
logger.error("Error: " + e.getMessage());
}
}
}
// ========== 场景 3:策略模式 ==========
interface SortStrategy {
void sort(int[] array);
}
static class BubbleSort implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Bubble Sort");
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - 1 - i; j++) {
if (array[j] > array[j + 1]) {
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
}
static class QuickSort implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Quick Sort");
quickSort(array, 0, array.length - 1);
}
private void quickSort(int[] array, int low, int high) {
if (low < high) {
int pi = partition(array, low, high);
quickSort(array, low, pi - 1);
quickSort(array, pi + 1, high);
}
}
private int partition(int[] array, int low, int high) {
int pivot = array[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (array[j] < pivot) {
i++;
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
int temp = array[i + 1];
array[i + 1] = array[high];
array[high] = temp;
return i + 1;
}
}
static class MergeSort implements SortStrategy {
@Override
public void sort(int[] array) {
System.out.println("Using Merge Sort");
mergeSort(array, 0, array.length - 1);
}
private void mergeSort(int[] array, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(array, left, mid);
mergeSort(array, mid + 1, right);
merge(array, left, mid, right);
}
}
private void merge(int[] array, int left, int mid, int right) {
// 归并逻辑
}
}
/**
* 排序器:运行时切换排序策略
*/
static class Sorter {
private SortStrategy strategy;
public void setStrategy(SortStrategy strategy) {
this.strategy = strategy;
}
public void executeSort(int[] array) {
if (strategy == null) {
System.out.println("No sorting strategy set");
return;
}
strategy.sort(array); // 多态调用
}
}
// ========== 场景 4:工厂模式 + 多态 ==========
interface Database {
void connect();
void query(String sql);
void disconnect();
}
static class MySQLDatabase implements Database {
@Override
public void connect() {
System.out.println("Connecting to MySQL...");
}
@Override
public void query(String sql) {
System.out.println("MySQL Query: " + sql);
}
@Override
public void disconnect() {
System.out.println("Disconnecting from MySQL");
}
}
static class PostgreSQLDatabase implements Database {
@Override
public void connect() {
System.out.println("Connecting to PostgreSQL...");
}
@Override
public void query(String sql) {
System.out.println("PostgreSQL Query: " + sql);
}
@Override
public void disconnect() {
System.out.println("Disconnecting from PostgreSQL");
}
}
static class MongoDBDatabase implements Database {
@Override
public void connect() {
System.out.println("Connecting to MongoDB...");
}
@Override
public void query(String sql) {
System.out.println("MongoDB Query: " + sql);
}
@Override
public void disconnect() {
System.out.println("Disconnecting from MongoDB");
}
}
/**
* 数据库工厂
*/
static class DatabaseFactory {
public static Database createDatabase(String type) {
switch (type.toLowerCase()) {
case "mysql":
return new MySQLDatabase();
case "postgresql":
return new PostgreSQLDatabase();
case "mongodb":
return new MongoDBDatabase();
default:
throw new IllegalArgumentException("Unknown database type: " + type);
}
}
}
/**
* 数据访问层:使用多态处理不同数据库
*/
static class DataAccessLayer {
private Database database;
public DataAccessLayer(String dbType) {
this.database = DatabaseFactory.createDatabase(dbType);
}
public void executeQuery(String sql) {
database.connect(); // 多态调用
database.query(sql); // 多态调用
database.disconnect(); // 多态调用
}
}
// ========== 测试所有场景 ==========
public static void main(String[] args) {
System.out.println("========== 场景 1:支付系统 ==========");
Order order = new Order(99.99);
// 使用信用卡支付
order.setPaymentMethod(new CreditCardPayment("1234-5678-9012-3456"));
order.checkout();
// 切换为 PayPal
order.setPaymentMethod(new PayPalPayment("user@example.com"));
order.checkout();
// 切换为微信支付
order.setPaymentMethod(new WeChatPayment("13800138000"));
order.checkout();
System.out.println("\n========== 场景 2:日志系统 ==========");
// 使用控制台日志
Application app1 = new Application(new ConsoleLogger());
app1.start();
app1.processData();
// 切换为文件日志
Application app2 = new Application(new FileLogger("app.log"));
app2.start();
app2.processData();
// 切换为数据库日志
Application app3 = new Application(new DatabaseLogger("jdbc:mysql://localhost/logs"));
app3.start();
app3.processData();
System.out.println("\n========== 场景 3:策略模式 ==========");
int[] data = {64, 34, 25, 12, 22, 11, 90};
Sorter sorter = new Sorter();
// 使用冒泡排序
sorter.setStrategy(new BubbleSort());
sorter.executeSort(data.clone());
// 切换为快速排序
sorter.setStrategy(new QuickSort());
sorter.executeSort(data.clone());
// 切换为归并排序
sorter.setStrategy(new MergeSort());
sorter.executeSort(data.clone());
System.out.println("\n========== 场景 4:工厂模式 ==========");
// 使用 MySQL
DataAccessLayer dal1 = new DataAccessLayer("mysql");
dal1.executeQuery("SELECT * FROM users");
// 切换为 PostgreSQL
DataAccessLayer dal2 = new DataAccessLayer("postgresql");
dal2.executeQuery("SELECT * FROM products");
// 切换为 MongoDB
DataAccessLayer dal3 = new DataAccessLayer("mongodb");
dal3.executeQuery("db.orders.find()");
}
}
说明:
- 支付系统(场景 1):通过设置
PaymentMethod,动态切换支付方式(信用卡、PayPal、微信支付),展示了如何通过多态来处理不同支付方式。 - 日志系统(场景 2):通过日志记录器接口
Logger,切换控制台日志、文件日志和数据库日志,展示多态如何适配不同日志输出方式。 - 策略模式(场景 3):通过
SortStrategy接口,运行时切换排序算法(冒泡排序、快速排序、归并排序),展示如何使用策略模式。 - 工厂模式 + 多态(场景 4):通过
Database接口,动态选择数据库(MySQL、PostgreSQL、MongoDB),展示了工厂模式与多态结合的使用。
四、Java OOP 的高级特性
4.1 单继承机制
/**
* Java 为什么不支持多重继承?
*
* 问题:菱形继承问题(Diamond Problem)
*/
public class SingleInheritanceDemo {
// ========== 菱形继承问题示例(假设 Java 支持多继承) ==========
/**
* 假设的场景:
*
* A
* / \
* B C
* \ /
* D
*
* 如果 B 和 C 都重写了 A 的方法,D 继承 B 和 C,
* 那么 D 调用该方法时应该用哪个版本?
*/
static class A {
public void display() {
System.out.println("A");
}
}
// ❌ Java 不支持
// class D extends B, C { } // 编译错误
/**
* Java 的解决方案:单继承 + 接口多实现
*/
static class B extends A {
@Override
public void display() {
System.out.println("B");
}
}
static class C extends A {
@Override
public void display() {
System.out.println("C");
}
}
// ✅ D 只能选择继承一个类
static class D extends B {
// 只继承 B 的实现
}
/**
* 单继承的优势:
*
* ✅ 1. 避免菱形继承问题
* ✅ 2. 简化继承关系
* ✅ 3. 降低复杂度
* ✅ 4. 提高代码可读性
*/
}
4.2 接口多实现
/**
* Java 通过接口实现"多重继承"的效果
*/
public class MultipleInterfaceDemo {
// ========== 多个接口 ==========
// Flyable 接口:定义了飞行和起飞行为
interface Flyable {
void fly();
default void takeOff() {
System.out.println("Taking off...");
}
}
// Swimmable 接口:定义了游泳和潜水行为
interface Swimmable {
void swim();
default void dive() {
System.out.println("Diving...");
}
}
// Runnable 接口:定义了奔跑和冲刺行为
interface Runnable {
void run();
default void sprint() {
System.out.println("Sprinting...");
}
}
// ========== 实现多个接口 ==========
/**
* Duck 类实现了 Flyable, Swimmable 和 Runnable 接口
* 拥有飞行、游泳、奔跑的能力
*/
static class Duck implements Flyable, Swimmable, Runnable {
@Override
public void fly() {
System.out.println("Duck is flying");
}
@Override
public void swim() {
System.out.println("Duck is swimming");
}
@Override
public void run() {
System.out.println("Duck is running");
}
}
/**
* Fish 类只实现了 Swimmable 接口
*/
static class Fish implements Swimmable {
@Override
public void swim() {
System.out.println("Fish is swimming");
}
}
/**
* Bird 类实现了 Flyable 和 Runnable 接口
*/
static class Bird implements Flyable, Runnable {
@Override
public void fly() {
System.out.println("Bird is flying");
}
@Override
public void run() {
System.out.println("Bird is running");
}
}
// ========== 接口冲突问题 ==========
// 定义两个接口,它们有相同的默认方法 display
interface Interface1 {
default void display() {
System.out.println("Interface1");
}
}
interface Interface2 {
default void display() {
System.out.println("Interface2");
}
}
/**
* 如果两个接口有相同的默认方法,必须在实现类中显式重写
*/
static class MyClass implements Interface1, Interface2 {
@Override
public void display() {
// 必须重写以解决冲突
// 方式 1:提供自己的实现
System.out.println("MyClass");
// 方式 2:调用某个接口的默认实现
// Interface1.super.display();
// 或
// Interface2.super.display();
}
}
// ========== 接口继承接口 ==========
interface Animal {
void eat();
}
interface Pet extends Animal {
void play();
}
interface WildAnimal extends Animal {
void hunt();
}
/**
* 接口可以继承多个接口
*/
interface Creature extends Flyable, Swimmable {
void breathe();
}
static class Dragon implements Creature {
@Override
public void fly() {
System.out.println("Dragon is flying");
}
@Override
public void swim() {
System.out.println("Dragon is swimming");
}
@Override
public void breathe() {
System.out.println("Dragon is breathing fire");
}
}
// ========== 测试 ==========
public static void main(String[] args) {
System.out.println("========== Duck(多接口实现) ==========");
Duck duck = new Duck();
duck.fly();
duck.swim();
duck.run();
duck.takeOff(); // 默认方法
duck.dive(); // 默认方法
duck.sprint(); // 默认方法
System.out.println("\n========== 多态 ==========");
// Duck 可以被视为多种类型
Flyable flyable = duck;
flyable.fly();
Swimmable swimmable = duck;
swimmable.swim();
Runnable runnable = duck;
runnable.run();
System.out.println("\n========== 接口冲突解决 ==========");
MyClass obj = new MyClass();
obj.display();
System.out.println("\n========== Dragon(接口继承) ==========");
Dragon dragon = new Dragon();
dragon.fly();
dragon.swim();
dragon.breathe();
dragon.takeOff(); // 继承自 Flyable
dragon.dive(); // 继承自 Swimmable
}
}
- 多个接口:
- 定义了三个接口
Flyable、Swimmable和Runnable,它们包含了飞行、游泳、奔跑的行为,且每个接口有一个默认方法。
- 定义了三个接口
- 实现多个接口:
Duck类实现了所有三个接口(Flyable、Swimmable和Runnable),具备飞行、游泳、奔跑的功能。Fish类只实现了Swimmable接口,具备游泳功能。Bird类实现了Flyable和Runnable接口,具备飞行和奔跑的功能。
- 接口冲突:
Interface1和Interface2都有display方法,如果实现这两个接口,需要在MyClass中重写display方法来解决冲突,可以选择自定义实现或调用某个接口的默认实现。
- 接口继承:
Creature接口继承了Flyable和Swimmable,并定义了breathe方法,Dragon类实现了Creature接口,具备飞行、游泳和呼吸的能力。
- 多态:
Duck类对象可以被作为Flyable、Swimmable和Runnable类型使用,展示了接口的多态特性。
- 测试:
main方法测试了各个场景,展示了如何使用多个接口、如何解决接口冲突以及如何利用接口继承创建多功能类。
核心概念:
- 多接口实现: 类可以实现多个接口,从而实现多重功能。
- 默认方法: 接口可以提供默认方法,在实现类中不必实现。
- 接口冲突: 如果多个接口定义了相同的默认方法,必须在实现类中显式重写该方法。
- 接口继承: 接口可以继承多个接口,创建更复杂的接口层次结构。
4.3 接口 vs 抽象类:
接口(Interface):
- ✅ 支持多实现
- ✅ 所有方法默认是 public abstract(JDK 8 前)
- ✅ 只能有常量(public static final)
- ✅ 支持默认方法和静态方法(JDK 8+)
- ✅ 表示"能做什么"(能力)
抽象类(Abstract Class):
- ✅ 只支持单继承
- ✅ 可以有任意访问修饰符
- ✅ 可以有实例变量
- ✅ 可以有构造器
- ✅ 表示"是什么"(本质)
⬅️ 面向对象or面向过程 🏠 00-Java ➡️ 面向对象设计的SOLID原则
💬 评论