Appearance
面向对象
类与对象
什么是面向对象?
面向对象(OOP) 是一种编程思想,将现实世界抽象为对象,通过对象之间的交互来解决问题。
┌─────────────────────────────────────────────────────────────┐
│ 面向对象 vs 面向过程 │
├─────────────────────────────────────────────────────────────┤
│ 面向过程 │ 面向对象 │
│ ───────────── │ ───────────── │
│ • 以函数为单位 │ • 以对象为单位 │
│ • 数据和操作分离 │ • 数据和操作封装在一起 │
│ • 适合简单逻辑 │ • 适合复杂业务逻辑 │
│ • 示例:C语言 │ • 示例:Java、C++ │
└─────────────────────────────────────────────────────────────┘面向对象的三大特征:
- 封装:保护内部数据,暴露必要接口
- 继承:复用已有代码,实现类型层次
- 多态:同一接口,不同实现
类的定义
类的基本结构
java
public class Person {
// 成员变量(属性)
private String name;
private int age;
// 构造方法 - 用于创建对象
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法(行为)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄不合法");
}
this.age = age;
}
// 重写 toString 方法 - 调试友好
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}创建对象
java
// 使用无参构造
Person p1 = new Person();
p1.setName("张三");
p1.setAge(25);
// 使用有参构造
Person p2 = new Person("李四", 30);封装
为什么要封装?
┌─────────────────────────────────────────┐
│ 封装的作用 │
├─────────────────────────────────────────┤
│ 1. 隐藏实现细节 → 保护数据安全 │
│ 2. 提供公共访问 → 统一接口规范 │
│ 3. 便于修改维护 → 代码更健壮 │
│ 4. 提高复用性 → 模块独立可重用 │
└─────────────────────────────────────────┘封装的实现
原则:将属性私有化(private),提供公共 getter/setter
java
public class User {
// ❌ 错误:属性直接暴露
public String username;
public String password;
// ✅ 正确:封装属性
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
// 密码加密存储
this.password = encrypt(password);
}
public boolean verifyPassword(String input) {
return this.password.equals(encrypt(input));
}
}💡 面试点:IDE 自动生成的 getter/setter 和手写有什么区别?
java
// IDE 生成的简单 getter/setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 实际项目中可能需要增强版(加入业务逻辑)
public void setName(String name) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("姓名不能为空");
}
this.name = name.trim();
}继承
继承的基本概念
┌─────────────────┐
│ Animal │
│ - name │
│ - age │
│ + eat() │
│ + sleep() │
└────────┬────────┘
│
┌────────────────┴────────────────┐
│ │
┌───────────▼───────────┐ ┌──────────────▼──────────────┐
│ Dog │ │ Cat │
│ - breed │ │ - color │
│ + bark() │ │ + meow() │
│ + catchBall() │ │ + scratch() │
└───────────────────────┘ └─────────────────────────────┘
Dog 和 Cat 继承了 Animal,复用了 name、age、eat()、sleep()继承的实现
java
// 父类
public class Animal {
protected String name;
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println(name + "正在吃东西");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
}
// 子类
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // 调用父类构造
this.breed = breed;
}
public void bark() {
System.out.println(name + "汪汪叫");
}
// 重写父类方法
@Override
public void eat() {
System.out.println(name + "正在吃狗粮");
}
}super 关键字
java
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // 调用父类构造方法
this.breed = breed;
}
public void show() {
super.eat(); // 调用父类的 eat 方法
System.out.println("品种:" + breed);
}
@Override
public void eat() {
System.out.println("Dog 重写的 eat");
super.eat(); // 调用父类的 eat 方法
}
}💡 面试点:this 和 super 的区别?
| 区别 | this | super |
|---|---|---|
| 指向 | 当前对象 | 父类对象 |
| 用途 | 调用本类成员 | 调用父类成员 |
| 构造 | this() 调用本类其他构造 | super() 调用父类构造 |
| 位置 | 必须在构造器首行 | 必须在构造器首行 |
多态
多态的三要素
┌─────────────────────────────────────────────────────────────┐
│ 多态的三要素 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 继承关系 → 父子类之间 │
│ │
│ 2. 方法重写 → 子类重写父类方法 │
│ │
│ 3. 父类引用指向子类对象 → Animal dog = new Dog(); │
│ │
└─────────────────────────────────────────────────────────────┘向上转型(自动)
java
// 父类引用指向子类对象
Animal animal = new Dog("旺财", 3, "金毛");
animal.eat(); // 调用的是 Dog 重写后的 eat
animal.sleep(); // 调用的是 Animal 的 sleep
// ❌ 编译错误:animal 是 Animal 类型,不能调用子类独有方法
animal.bark(); // 编译错误!向下转型(强制)
java
Animal animal = new Dog("旺财", 3, "金毛");
// ✅ 向下转型
Dog dog = (Dog) animal;
dog.bark(); // 现在可以调用了
// ⚠️ 危险:类型转换异常
Animal cat = new Cat("咪咪", 2, "白色");
// Dog dog2 = (Dog) cat; // ClassCastException!instanceof 关键字
💡 面试高频:向下转型前一定要用 instanceof 判断!
java
public void makeSound(Animal animal) {
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.bark();
} else if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.meow();
}
}
// Java 16+ 新写法 (Pattern Matching)
public void makeSound(Animal animal) {
if (animal instanceof Dog dog) {
dog.bark();
} else if (animal instanceof Cat cat) {
cat.meow();
}
}抽象类与接口
抽象类
抽象类:用 abstract 修饰,包含抽象方法的类
java
// 抽象类
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象方法 - 没有方法体,子类必须重写
public abstract double area();
public abstract double perimeter();
// 具体方法 - 子类可选重写
public void print() {
System.out.println("颜色:" + color);
}
}
// 子类
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
@Override
public double perimeter() {
return 2 * Math.PI * radius;
}
}抽象类特点:
- 不能实例化(不能
new Shape()) - 可以包含抽象方法和具体方法
- 单继承(一个类只能继承一个抽象类)
- 构造方法可以被子类调用
接口
接口:一种契约,定义行为规范
java
// 接口 - Java 8+ 支持 default 和 static 方法
public interface Drawable {
// 常量(默认 public static final)
int MAX_SIZE = 1000;
// 抽象方法
void draw();
// Java 8+ default 方法 - 提供默认实现
default void print() {
System.out.println("打印图形");
}
// Java 8+ static 方法
static Drawable create() {
return new Circle("红色", 5);
}
}
// 实现类
public class Rectangle implements Drawable {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("绘制矩形");
}
}抽象类 vs 接口
💡 面试高频对比:
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 继承 | 单继承 | 多实现 |
| 构造方法 | 可以有 | 不能有 |
| 属性 | 任意类型 | 只能是常量 |
| 方法 | 任意方法 | 抽象/ default/ static |
| 实现关键字 | extends | implements |
| 设计理念 | "是什么"(is-a) | "能做什么"(can-do) |
java
// 抽象类 - 表达"是什么"
public abstract class Flyable {
protected double speed;
public abstract void fly();
}
public class Bird extends Flyable {
@Override
public void fly() {
System.out.println("鸟儿飞翔");
}
}
// 接口 - 表达"能做什么"
public interface Swimable {
void swim();
}
public interface Divable {
void dive();
}
public class Duck extends Flyable implements Swimable, Divable {
@Override
public void fly() { }
@Override
public void swim() { }
@Override
public void dive() { }
}内部类
成员内部类
java
public class Outer {
private String outerVar = "外部类变量";
public class Inner {
private String innerVar = "内部类变量";
public void show() {
System.out.println(outerVar); // 可以访问外部类私有成员
System.out.println(innerVar);
}
}
}
// 使用
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.show();静态内部类
java
public class Outer {
private static String staticVar = "静态变量";
public static class StaticInner {
public void show() {
// 只能访问外部类静态成员
System.out.println(staticVar);
}
}
}
// 使用 - 不需要创建外部类对象
Outer.StaticInner inner = new Outer.StaticInner();局部内部类
java
public class Outer {
public void method() {
// 定义在方法内部的类
class LocalInner {
private String name = "局部内部类";
public void show() {
System.out.println(name);
}
}
LocalInner inner = new LocalInner();
inner.show();
}
}匿名内部类
💡 面试高频:匿名内部类的应用场景
java
// 场景1:简化实现接口
Runnable task = new Runnable() {
@Override
public void run() {
System.out.println("线程任务执行中");
}
};
new Thread(task).start();
// 场景2:简化继承抽象类
abstract class Animal {
abstract void cry();
}
Animal dog = new Animal() {
@Override
void cry() {
System.out.println("汪汪汪");
}
};
// 场景3:事件监听 (Android 开发常见)
// button.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// // 处理点击事件
// }
// });关键字总结
this 关键字
java
public class Person {
private String name;
public Person(String name) {
// this 区分成员变量和局部变量
this.name = name;
}
public Person getThis() {
// this 返回当前对象引用
return this;
}
}static 关键字
详见 基础语法 中的 static 详解
final 关键字
详见 基础语法 中的 final 详解
总结
面向对象核心知识点:
| 概念 | 面试频率 | 实战重要性 |
|---|---|---|
| 封装 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 继承 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 多态 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 抽象类 vs 接口 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 内部类 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
⚠️ 易错点提醒:
- 构造方法不能被继承(子类通过 super 调用)
- private 成员不能被继承
- 向上转型安全,向下转型需要 instanceof
- 抽象类有构造方法但不能实例化
- 接口属性默认
public static final,方法默认public abstract