面向对象编程 (Object-Oriented Programming)¶
Java的核心思想,理解封装、继承、多态是编写高质量代码的基础
目录¶
1. 类与对象 (Class and Object)¶
1.1 类的定义 (Class Definition)¶
类是对象的模板,定义了对象的属性和行为。
/**
* 学生类示例
* Student Class Example
*
* 类的组成:
* 1. 成员变量(属性) - Member Variables (Fields)
* 2. 构造器 - Constructors
* 3. 成员方法 - Member Methods
*/
public class Student {
// 1. 成员变量(实例变量) - Instance Variables
private String name; // 姓名
private int age; // 年龄
private String studentId; // 学号
// 静态变量(类变量) - Static Variables
private static int studentCount = 0; // 学生总数
// 常量 - Constant
private static final String SCHOOL_NAME = "清华大学";
// 2. 构造器 - Constructors
/**
* 无参构造器 (No-Argument Constructor)
* 如果不显式定义,Java会提供默认构造器
*/
public Student() {
studentCount++;
}
/**
* 有参构造器 (Parameterized Constructor)
*/
public Student(String name, int age) {
this.name = name; // this关键字指向当前对象
this.age = age;
studentCount++;
}
/**
* 全参构造器 (All-Args Constructor)
*/
public Student(String name, int age, String studentId) {
this(name, age); // 调用其他构造器,必须在第一行
this.studentId = studentId;
}
// 3. 成员方法 - Member Methods
/**
* 实例方法 (Instance Method)
* 需要通过对象调用
*/
public void study() {
System.out.println(name + " 正在学习...");
}
/**
* 带参数和返回值的方法
* Method with Parameters and Return Value
*/
public int getAgeAfterYears(int years) {
return this.age + years;
}
/**
* 静态方法 (Static Method)
* 可以通过类名直接调用
*/
public static int getStudentCount() {
return studentCount;
}
// Getter和Setter方法
public String getName() {
return name;
}
public void setName(String name) {
// 可以在setter中添加验证逻辑
if (name != null && !name.isEmpty()) {
this.name = name;
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0 && age < 150) {
this.age = age;
}
}
/**
* 重写Object类的toString方法
* Override toString() method
*/
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age +
", studentId='" + studentId + "'}";
}
}
1.2 对象的创建和使用 (Object Creation and Usage)¶
/**
* 对象使用示例
* Object Usage Example
*/
public class StudentTest {
public static void main(String[] args) {
// 创建对象 (Create Object)
Student student1 = new Student();
student1.setName("张三");
student1.setAge(20);
// 使用有参构造器创建对象
Student student2 = new Student("李四", 22);
// 调用实例方法
student1.study(); // 输出:张三 正在学习...
// 调用静态方法 - 通过类名调用(推荐)
System.out.println("学生总数: " + Student.getStudentCount());
// 访问对象信息
System.out.println(student2.toString());
// 对象比较
Student student3 = new Student("李四", 22);
System.out.println(student2 == student3); // false - 不同对象
// 对象引用
Student student4 = student2; // student4和student2指向同一对象
System.out.println(student2 == student4); // true - 同一对象
}
}
1.3 this 和 static 关键字¶
this 关键字¶
- 指向当前对象的引用
- 三种用法:
- 访问成员变量:
this.name - 调用其他构造器:
this(...) - 返回当前对象:
return this;
public class Person {
private String name;
public Person(String name) {
this.name = name; // 区分成员变量和参数
}
public Person setName(String name) {
this.name = name;
return this; // 返回当前对象,支持链式调用
}
}
static 关键字¶
- 属于类而非对象
- 可以修饰: 变量、方法、代码块、内部类
public class Counter {
// 静态变量 - 所有对象共享
private static int count = 0;
// 实例变量 - 每个对象独立
private int instanceCount = 0;
// 静态代码块 - 类加载时执行一次
static {
System.out.println("Counter类被加载");
count = 100;
}
// 实例代码块 - 每次创建对象时执行
{
System.out.println("创建Counter对象");
instanceCount = 1;
}
// 静态方法
public static void increment() {
count++;
// 注意:静态方法不能访问实例变量和实例方法
// instanceCount++; // 编译错误!
}
// 实例方法可以访问静态成员
public void print() {
System.out.println("count=" + count +
", instanceCount=" + instanceCount);
}
}
2. 封装 (Encapsulation)¶
封装是隐藏对象的内部实现细节,只暴露必要的接口。
2.1 访问修饰符 (Access Modifiers)¶
| 修饰符 | 同一类 | 同一包 | 子类 | 不同包 | 说明 |
|---|---|---|---|---|---|
private |
✅ | ❌ | ❌ | ❌ | 最严格 |
默认(package-private) |
✅ | ✅ | ❌ | ❌ | 包可见 |
protected |
✅ | ✅ | ✅ | ❌ | 子类可见 |
public |
✅ | ✅ | ✅ | ✅ | 公开 |
/**
* 封装示例:银行账户
* Encapsulation Example: Bank Account
*/
public class BankAccount {
// private:隐藏内部数据
private String accountNumber;
private double balance;
private String password;
public BankAccount(String accountNumber, String password) {
this.accountNumber = accountNumber;
this.password = password;
this.balance = 0.0;
}
/**
* 存款方法 (Deposit)
* 提供公开接口,内部进行验证
*/
public boolean deposit(double amount) {
if (amount <= 0) {
System.out.println("存款金额必须大于0");
return false;
}
balance += amount;
System.out.println("存款成功,当前余额: " + balance);
return true;
}
/**
* 取款方法 (Withdraw)
* 需要密码验证,体现封装的安全性
*/
public boolean withdraw(String password, double amount) {
// 验证密码
if (!this.password.equals(password)) {
System.out.println("密码错误");
return false;
}
// 验证金额
if (amount <= 0) {
System.out.println("取款金额必须大于0");
return false;
}
// 验证余额
if (amount > balance) {
System.out.println("余额不足");
return false;
}
balance -= amount;
System.out.println("取款成功,当前余额: " + balance);
return true;
}
/**
* 查询余额 (Check Balance)
* 需要密码验证
*/
public double getBalance(String password) {
if (!this.password.equals(password)) {
System.out.println("密码错误");
return -1;
}
return balance;
}
// 只提供getter,不提供setter,保护账号不被修改
public String getAccountNumber() {
return accountNumber;
}
}
2.2 封装的优势 ✅¶
- 数据安全:隐藏内部数据,防止非法访问
- 灵活性:修改内部实现不影响外部调用
- 可维护性:降低耦合,便于维护
- 数据验证:在setter中添加验证逻辑
3. 继承 (Inheritance)¶
继承是子类继承父类的属性和方法,实现代码复用。
3.1 继承的基本语法¶
/**
* 父类:动物
* Parent Class: Animal
*/
public class Animal {
// protected:子类可以访问
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 void makeSound() {
System.out.println(name + " 发出声音");
}
}
/**
* 子类:狗
* Child Class: Dog
*
* extends关键字实现继承
*/
public class Dog extends Animal {
// 子类特有的属性
private String breed; // 品种
/**
* 子类构造器
* 必须调用父类构造器
*/
public Dog(String name, int age, String breed) {
super(name, age); // 调用父类构造器,必须在第一行
this.breed = breed;
}
/**
* 方法重写 (Method Overriding)
* 子类重新实现父类的方法
*/
@Override // 注解,帮助编译器检查是否正确重写
public void makeSound() {
System.out.println(name + " 汪汪叫");
}
/**
* 子类特有的方法
* Dog-Specific Method
*/
public void fetch() {
System.out.println(name + " 正在捡球");
}
/**
* 调用父类方法
* Call Parent Method
*/
public void parentMakeSound() {
super.makeSound(); // 使用super调用父类方法
}
}
/**
* 子类:猫
* Child Class: Cat
*/
public class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}
@Override
public void makeSound() {
System.out.println(name + " 喵喵叫");
}
public void climb() {
System.out.println(name + " 正在爬树");
}
}
3.2 继承的使用¶
/**
* 继承使用示例
* Inheritance Usage Example
*/
public class InheritanceDemo {
public static void main(String[] args) {
// 创建子类对象
Dog dog = new Dog("旺财", 3, "金毛");
Cat cat = new Cat("小花", 2);
// 调用继承的方法
dog.eat(); // 继承自Animal
dog.sleep(); // 继承自Animal
// 调用重写的方法
dog.makeSound(); // 输出:旺财 汪汪叫
cat.makeSound(); // 输出:小花 喵喵叫
// 调用子类特有的方法
dog.fetch();
cat.climb();
// 向上转型 (Upcasting) - 子类对象赋给父类变量
Animal animal1 = dog; // 自动转型
Animal animal2 = cat;
animal1.makeSound(); // 输出:旺财 汪汪叫(多态)
// animal1.fetch(); // 编译错误!父类引用不能调用子类特有方法
// 向下转型 (Downcasting) - 需要强制转型
if (animal1 instanceof Dog) {
Dog myDog = (Dog) animal1; // 强制转型
myDog.fetch(); // 现在可以调用了
}
}
}
3.3 方法重写的规则 (Override Rules)¶
必须遵守的规则 ⚠️¶
- 方法名相同
- 参数列表相同
- 返回类型相同或是子类(协变返回类型)
- 访问修饰符不能更严格(可以更宽松)
- 不能抛出新的或更广的检查异常
class Parent {
protected Object method() throws IOException {
return new Object();
}
}
class Child extends Parent {
// ✅ 合法:返回类型是子类
@Override
public String method() throws IOException {
return "Hello";
}
// ❌ 编译错误:访问修饰符更严格
// @Override
// private Object method() { }
// ❌ 编译错误:抛出了新的检查异常
// @Override
// public Object method() throws SQLException { }
}
3.4 super 关键字¶
- 调用父类构造器:
super(...) - 调用父类方法:
super.method() - 访问父类变量:
super.field
class Vehicle {
protected int speed = 100;
public Vehicle() {
System.out.println("Vehicle构造器");
}
public void move() {
System.out.println("交通工具移动");
}
}
class Car extends Vehicle {
private int speed = 200; // 隐藏父类变量
public Car() {
super(); // 调用父类构造器
System.out.println("Car构造器");
}
public void displaySpeed() {
System.out.println("子类speed: " + this.speed); // 200
System.out.println("父类speed: " + super.speed); // 100
}
@Override
public void move() {
super.move(); // 先调用父类方法
System.out.println("汽车在路上行驶");
}
}
3.5 继承的注意事项 ⚠️¶
- Java只支持单继承:一个类只能继承一个父类
- 构造器不能被继承:但子类构造器必须调用父类构造器
- 私有成员不能被继承:但可以通过public/protected方法访问
- final类不能被继承:
final class CannotExtend { } - final方法不能被重写:
public final void method() { } - 避免在构造器中调用可重写的方法:可能导致意外行为
4. 多态 (Polymorphism)¶
多态是同一操作作用于不同对象,产生不同的执行结果。
4.1 多态的实现方式¶
- 方法重载 (Overload) - 编译时多态
- 方法重写 (Override) - 运行时多态
4.2 运行时多态示例¶
/**
* 多态示例:图形计算
* Polymorphism Example: Shape Calculation
*/
abstract class Shape {
protected String name;
public Shape(String name) {
this.name = name;
}
// 抽象方法,子类必须实现
public abstract double getArea();
public abstract double getPerimeter();
public void display() {
System.out.println(name + " - 面积: " + getArea() +
", 周长: " + getPerimeter());
}
}
/**
* 圆形
* Circle
*/
class Circle extends Shape {
private double radius;
public Circle(double radius) {
super("圆形");
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * radius;
}
}
/**
* 矩形
* Rectangle
*/
class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
super("矩形");
this.width = width;
this.height = height;
}
@Override
public double getArea() {
return width * height;
}
@Override
public double getPerimeter() {
return 2 * (width + height);
}
}
/**
* 多态演示
* Polymorphism Demo
*/
public class PolymorphismDemo {
public static void main(String[] args) {
// 父类引用指向子类对象 - 多态的体现
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);
// 同一方法调用,不同的执行结果
circle.display(); // 调用Circle的实现
rectangle.display(); // 调用Rectangle的实现
// 多态数组
Shape[] shapes = {
new Circle(3),
new Rectangle(5, 10),
new Circle(7)
};
// 统一处理不同类型的对象
double totalArea = 0;
for (Shape shape : shapes) {
totalArea += shape.getArea(); // 多态:运行时决定调用哪个方法
}
System.out.println("总面积: " + totalArea);
}
}
4.3 多态的三个必要条件¶
- 继承:必须有子类继承父类或实现接口
- 重写:子类必须重写父类的方法
- 向上转型:父类引用指向子类对象
4.4 instanceof 运算符¶
/**
* instanceof 使用示例
* instanceof Operator Example
*/
public class InstanceofDemo {
public static void main(String[] args) {
Animal animal = new Dog("旺财", 3, "金毛");
// 判断对象的实际类型
if (animal instanceof Dog) {
System.out.println("这是一只狗");
Dog dog = (Dog) animal;
dog.fetch();
}
// 继承关系也会返回true
System.out.println(animal instanceof Animal); // true
System.out.println(animal instanceof Dog); // true
System.out.println(animal instanceof Cat); // false
// null检查
Animal nullAnimal = null;
System.out.println(nullAnimal instanceof Animal); // false
}
}
4.5 多态的优势 ✅¶
- 可扩展性:添加新类不需要修改现有代码
- 可维护性:统一接口,简化代码
- 灵活性:运行时动态绑定方法
- 解耦:降低类之间的耦合度
5. 接口 (Interface)¶
接口是一种抽象类型,定义了类应该实现的行为规范。
5.1 接口的定义和实现¶
/**
* 飞行接口
* Flyable Interface
*
* 接口中的方法默认是public abstract
* 接口中的变量默认是public static final
*/
public interface Flyable {
// 常量 - 自动添加public static final
int MAX_SPEED = 1000;
// 抽象方法 - 自动添加public abstract
void fly();
void land();
// Java 8+: 默认方法 (Default Method)
default void takeOff() {
System.out.println("起飞准备...");
fly();
}
// Java 8+: 静态方法 (Static Method)
static void checkWeather() {
System.out.println("检查天气状况");
}
// Java 9+: 私有方法 (Private Method)
private void log(String message) {
System.out.println("日志: " + message);
}
}
/**
* 游泳接口
* Swimmable Interface
*/
public interface Swimmable {
void swim();
}
/**
* 鸟类 - 实现飞行接口
* Bird - Implements Flyable Interface
*/
public class Bird implements Flyable {
private String name;
public Bird(String name) {
this.name = name;
}
@Override
public void fly() {
System.out.println(name + " 在天空飞翔");
}
@Override
public void land() {
System.out.println(name + " 降落到地面");
}
}
/**
* 鸭子 - 实现多个接口
* Duck - Implements Multiple Interfaces
*
* Java支持多接口实现,弥补单继承的限制
*/
public class Duck implements Flyable, Swimmable {
private String name;
public Duck(String name) {
this.name = name;
}
@Override
public void fly() {
System.out.println(name + " 飞得不太高");
}
@Override
public void land() {
System.out.println(name + " 降落到水面");
}
@Override
public void swim() {
System.out.println(name + " 在水中游泳");
}
}
5.2 接口的使用¶
/**
* 接口使用示例
* Interface Usage Example
*/
public class InterfaceDemo {
public static void main(String[] args) {
// 接口引用指向实现类对象
Flyable bird = new Bird("麻雀");
bird.fly();
bird.takeOff(); // 调用默认方法
// 静态方法通过接口名调用
Flyable.checkWeather();
// 多接口实现
Duck duck = new Duck("唐老鸭");
duck.fly();
duck.swim();
// 接口多态
Flyable flyable = duck;
flyable.fly();
Swimmable swimmable = duck;
swimmable.swim();
}
}
5.3 接口的特点¶
- 接口不能被实例化
- 接口中的方法默认是public abstract
- 接口中的变量默认是public static final
- 一个类可以实现多个接口
- 接口可以继承多个接口
// 接口继承接口
public interface A {
void methodA();
}
public interface B {
void methodB();
}
// 接口可以继承多个接口
public interface C extends A, B {
void methodC();
}
6. 抽象类 (Abstract Class)¶
抽象类是介于普通类和接口之间的一种类型。
6.1 抽象类的定义¶
/**
* 抽象类:员工
* Abstract Class: Employee
*
* 抽象类特点:
* 1. 不能被实例化
* 2. 可以有抽象方法和普通方法
* 3. 可以有成员变量
* 4. 可以有构造器
*/
public abstract class Employee {
// 成员变量
protected String name;
protected String id;
protected double baseSalary;
// 构造器
public Employee(String name, String id, double baseSalary) {
this.name = name;
this.id = id;
this.baseSalary = baseSalary;
}
// 抽象方法 - 子类必须实现
public abstract double calculateSalary();
// 普通方法 - 子类可以继承或重写
public void displayInfo() {
System.out.println("员工姓名: " + name);
System.out.println("员工ID: " + id);
System.out.println("工资: " + calculateSalary());
}
// 普通方法
public String getName() {
return name;
}
}
/**
* 全职员工
* FullTimeEmployee
*/
public class FullTimeEmployee extends Employee {
private double bonus;
public FullTimeEmployee(String name, String id,
double baseSalary, double bonus) {
super(name, id, baseSalary);
this.bonus = bonus;
}
@Override
public double calculateSalary() {
return baseSalary + bonus;
}
}
/**
* 兼职员工
* PartTimeEmployee
*/
public class PartTimeEmployee extends Employee {
private int hoursWorked;
private double hourlyRate;
public PartTimeEmployee(String name, String id,
int hoursWorked, double hourlyRate) {
super(name, id, 0); // 基本工资为0
this.hoursWorked = hoursWorked;
this.hourlyRate = hourlyRate;
}
@Override
public double calculateSalary() {
return hoursWorked * hourlyRate;
}
}
6.2 抽象类 vs 接口¶
| 维度 | 抽象类 | 接口 |
|---|---|---|
| 关键字 | abstract class | interface |
| 方法 | 可以有抽象和普通方法 | 主要是抽象方法(Java 8+可有默认方法) |
| 变量 | 可以有实例变量 | 只能有常量(public static final) |
| 构造器 | 可以有 | 不能有 |
| 继承 | 单继承 | 多实现 |
| 访问修饰符 | 任意 | 方法默认public |
| 使用场景 | 有共同实现的父类 | 定义行为规范 |
6.3 何时使用抽象类 vs 接口?¶
使用抽象类 ✅¶
- 多个类有共同的字段或方法
- 需要非public成员
- 需要提供部分实现
使用接口 ✅¶
- 定义行为规范
- 需要多重继承
- 不同继承树的类具有相同行为
// 示例:抽象类提供部分实现
public abstract class HttpServlet {
// 公共逻辑
public void service(HttpRequest request, HttpResponse response) {
String method = request.getMethod();
if ("GET".equals(method)) {
doGet(request, response);
} else if ("POST".equals(method)) {
doPost(request, response);
}
}
// 子类实现具体逻辑
protected abstract void doGet(HttpRequest request, HttpResponse response);
protected abstract void doPost(HttpRequest request, HttpResponse response);
}
// 示例:接口定义行为规范
public interface Comparable<T> {
int compareTo(T o);
}
7. 内部类 (Inner Classes)¶
内部类是定义在另一个类内部的类。
7.1 成员内部类 (Member Inner Class)¶
/**
* 外部类
* Outer Class
*/
public class Outer {
private String outerField = "外部类字段";
/**
* 成员内部类
* Member Inner Class
*
* 特点:
* 1. 可以访问外部类的所有成员(包括private)
* 2. 需要先创建外部类对象才能创建内部类对象
*/
public class Inner {
private String innerField = "内部类字段";
public void display() {
// 可以直接访问外部类成员
System.out.println("访问外部类字段: " + outerField);
System.out.println("内部类字段: " + innerField);
// 使用外部类名.this访问外部类实例
System.out.println(Outer.this.outerField);
}
}
public void test() {
// 外部类可以直接创建内部类对象
Inner inner = new Inner();
inner.display();
}
}
/**
* 使用示例
*/
public class InnerClassDemo {
public static void main(String[] args) {
// 先创建外部类对象
Outer outer = new Outer();
// 通过外部类对象创建内部类对象
Outer.Inner inner = outer.new Inner();
inner.display();
}
}
7.2 静态内部类 (Static Nested Class)¶
/**
* 静态内部类示例
* Static Nested Class Example
*/
public class OuterStatic {
private static String staticField = "静态字段";
private String instanceField = "实例字段";
/**
* 静态内部类
* Static Nested Class
*
* 特点:
* 1. 不依赖外部类实例
* 2. 只能访问外部类的静态成员
* 3. 可以有静态成员
*/
public static class StaticInner {
private static int count = 0;
public void display() {
// 可以访问外部类的静态成员
System.out.println("静态字段: " + staticField);
// 不能访问外部类的实例成员
// System.out.println(instanceField); // 编译错误!
}
}
}
/**
* 使用示例
*/
public class StaticInnerDemo {
public static void main(String[] args) {
// 不需要外部类对象,直接创建
OuterStatic.StaticInner inner = new OuterStatic.StaticInner();
inner.display();
}
}
7.3 局部内部类 (Local Inner Class)¶
/**
* 局部内部类示例
* Local Inner Class Example
*/
public class LocalInnerDemo {
private String field = "外部类字段";
public void method() {
final String localVar = "局部变量"; // 必须是final或effectively final
/**
* 局部内部类
* 定义在方法内部
*/
class LocalInner {
public void display() {
System.out.println(field); // 可以访问外部类成员
System.out.println(localVar); // 可以访问局部变量
}
}
// 在方法内使用
LocalInner inner = new LocalInner();
inner.display();
}
}
7.4 匿名内部类 (Anonymous Inner Class)¶
/**
* 匿名内部类示例
* Anonymous Inner Class Example
*/
public class AnonymousInnerDemo {
public static void main(String[] args) {
// 匿名内部类实现接口
Flyable flyable = new Flyable() {
@Override
public void fly() {
System.out.println("匿名类飞行");
}
@Override
public void land() {
System.out.println("匿名类降落");
}
};
flyable.fly();
// 匿名内部类继承抽象类
Animal animal = new Animal("匿名动物", 0) {
@Override
public void makeSound() {
System.out.println("未知声音");
}
};
animal.makeSound();
// Java 8 Lambda表达式可以替代单方法接口的匿名内部类
// Runnable task = () -> System.out.println("Lambda表达式");
}
}
7.5 内部类的应用场景¶
- 封装辅助类:工具类或辅助类只被外部类使用
- 事件处理:GUI编程中的事件监听器
- 迭代器实现:集合类的迭代器通常是内部类
- 回调机制:匿名内部类实现回调接口
8. 最佳实践 (Best Practices)¶
8.1 设计原则¶
- 单一职责原则 (SRP):一个类只负责一个功能
- 开闭原则 (OCP):对扩展开放,对修改关闭
- 里氏替换原则 (LSP):子类可以替换父类
- 接口隔离原则 (ISP):接口应该小而专注
- 依赖倒置原则 (DIP):依赖抽象而非具体实现
8.2 代码规范¶
// ✅ 好的实践
public class GoodPractice {
// 1. 成员变量私有化
private String name;
// 2. 提供getter/setter
public String getName() {
return name;
}
public void setName(String name) {
// 3. setter中进行验证
if (name != null && !name.isEmpty()) {
this.name = name;
}
}
// 4. 重写equals和hashCode
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
GoodPractice that = (GoodPractice) obj;
return Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
// 5. 重写toString
@Override
public String toString() {
return "GoodPractice{name='" + name + "'}";
}
}
9. 面试高频问题 (Frequently Asked Interview Questions)¶
Q1: 面向对象的三大特性是什么?⭐⭐⭐⭐⭐¶
答案:
- 封装 (Encapsulation)
- 隐藏内部实现,只暴露必要接口
-
通过private修饰符和public方法实现
-
继承 (Inheritance)
- 子类继承父类的属性和方法,实现代码复用
-
使用extends关键字
-
多态 (Polymorphism)
- 同一操作作用于不同对象,产生不同结果
- 通过方法重写和向上转型实现
Q2: 重载和重写的区别?⭐⭐⭐⭐⭐¶
答案:
| 维度 | 重载 (Overload) | 重写 (Override) |
|---|---|---|
| 位置 | 同一个类 | 父类和子类 |
| 方法名 | 相同 | 相同 |
| 参数列表 | 不同(重点) | 相同 |
| 返回类型 | 可以不同 | 相同或子类 |
| 访问修饰符 | 可以不同 | 不能更严格 |
| 异常 | 可以不同 | 不能更广 |
| 发生时机 | 编译期 | 运行期 |
| 多态 | 编译时多态 | 运行时多态 |
Q3: 接口和抽象类的区别?⭐⭐⭐⭐⭐¶
答案: 见6.2节
Q4: 什么是多态?如何实现?⭐⭐⭐⭐⭐¶
答案:
多态是指同一操作作用于不同对象,产生不同的执行结果。
实现方式: 1. 继承:子类继承父类或实现接口 2. 重写:子类重写父类方法 3. 向上转型:父类引用指向子类对象
好处: - 可扩展性:添加新类不需要修改现有代码 - 灵活性:运行时动态绑定 - 可维护性:统一接口,简化代码
Q5: super和this的区别?⭐⭐⭐⭐¶
答案:
| 关键字 | 作用 | 用法 |
|---|---|---|
| this | 当前对象的引用 | 1. 访问成员变量 2. 调用构造器 3. 返回当前对象 |
| super | 父类对象的引用 | 1. 调用父类构造器 2. 调用父类方法 3. 访问父类变量 |
Q6: 静态方法能被重写吗?⭐⭐⭐⭐¶
答案:
不能。静态方法属于类而不属于对象,不存在运行时多态。子类可以定义同名静态方法,但这是**方法隐藏**,不是重写。
class Parent {
public static void staticMethod() {
System.out.println("父类静态方法");
}
}
class Child extends Parent {
// 方法隐藏,不是重写
public static void staticMethod() {
System.out.println("子类静态方法");
}
}
// 调用时根据引用类型决定,不是实际对象类型
Parent p = new Child();
p.staticMethod(); // 输出:父类静态方法
Q7: 构造器可以被继承吗?⭐⭐⭐¶
答案:
不能。构造器不能被继承,但子类构造器必须调用父类构造器(显式或隐式)。
Q8: 内部类有哪些?各有什么特点?⭐⭐⭐⭐¶
答案:
| 类型 | 特点 | 使用场景 |
|---|---|---|
| 成员内部类 | 需要外部类实例,可访问外部类所有成员 | 紧密关联的辅助类 |
| 静态内部类 | 不需要外部类实例,只能访问静态成员 | 逻辑上分组的工具类 |
| 局部内部类 | 定义在方法内,作用域仅在方法内 | 临时使用的类 |
| 匿名内部类 | 没有名字,通常用于接口或抽象类的快速实现 | 事件处理、回调 |
Q9: 为什么要封装?⭐⭐⭐⭐¶
答案:
- 数据安全:隐藏内部数据,防止非法访问和修改
- 灵活性:修改内部实现不影响外部调用
- 可维护性:降低耦合,便于维护
- 数据验证:在setter中添加验证逻辑
- 只读/只写:通过提供或不提供getter/setter控制访问
Q10: Object类有哪些方法?⭐⭐⭐⭐¶
答案:
// Object类的主要方法
1. equals(Object obj) - 比较对象是否相等
2. hashCode() - 返回对象的哈希码
3. toString() - 返回对象的字符串表示
4. clone() - 克隆对象
5. getClass() - 获取对象的Class对象
6. notify() / notifyAll() - 线程通信
7. wait() - 线程等待
8. finalize() - 对象被GC前调用(已过时)
总结 (Summary)¶
本章介绍了Java面向对象编程的核心概念:
- ✅ 类与对象:Java程序的基本单位
- ✅ 封装:隐藏实现,保护数据
- ✅ 继承:代码复用,建立类层次
- ✅ 多态:灵活扩展,降低耦合
- ✅ 接口:定义行为规范,支持多实现
- ✅ 抽象类:提供部分实现的父类
- ✅ 内部类:封装辅助类
面向对象是Java的核心,建议:
- 理解概念:深刻理解封装、继承、多态的本质
- 实践应用:多写代码,体会OOP的优势
- 设计模式:学习设计模式,提升设计能力
- 阅读源码:阅读JDK源码,学习优秀设计
下一篇: 03 - Java高级特性 →
返回目录: Java 语言基础导航 ←