Skip to content

面向对象基础

Java 是一门面向对象的编程语言。面向对象编程(OOP)是一种程序设计思想,它将程序中的数据和操作数据的方法封装成对象。

面向对象概述

面向对象 vs 面向过程

text
┌─────────────────────────────────────────────────────────────────┐
│                   面向对象 vs 面向过程                            │
├─────────────────────────────────────────────────────────────────┤
│  面向过程:                                                       │
│    - 关注"怎么做"                                                │
│    - 以函数为中心                                                 │
│    - 数据和行为分离                                               │
│    - 示例:C 语言                                                 │
│                                                                 │
│  面向对象:                                                       │
│    - 关注"谁来做"                                                │
│    - 以对象为中心                                                 │
│    - 数据和行为封装在一起                                         │
│    - 示例:Java、Python                                          │
└─────────────────────────────────────────────────────────────────┘

面向对象三大特性

text
┌─────────────────────────────────────────────────────────────────┐
│                    面向对象三大特性                               │
├─────────────────────────────────────────────────────────────────┤
│  1. 封装:隐藏实现细节,提供公共访问方式                           │
│  2. 继承:子类继承父类的属性和方法                                 │
│  3. 多态:同一行为具有不同表现形式                                 │
└─────────────────────────────────────────────────────────────────┘

类与对象

类的定义

类是对象的模板,定义了对象的属性和行为。

java
/**
 * 学生类:定义学生的属性和行为
 */
public class Student {
    // 属性(成员变量)
    String name;      // 姓名
    int age;          // 年龄
    String major;     // 专业
    double score;     // 成绩
    
    // 方法(成员方法)
    /**
     * 学习方法
     */
    public void study() {
        System.out.println(name + "正在学习" + major);
    }
    
    /**
     * 考试方法
     * @param subject 科目
     * @param examScore 成绩
     */
    public void takeExam(String subject, double examScore) {
        this.score = examScore;
        System.out.println(name + "参加了" + subject + "考试,成绩:" + examScore);
    }
    
    /**
     * 自我介绍
     */
    public void introduce() {
        System.out.println("我是" + name + ",今年" + age + "岁,专业是" + major);
    }
}

对象的创建和使用

java
public class StudentDemo {
    public static void main(String[] args) {
        // 创建对象:类名 对象名 = new 类名();
        Student student1 = new Student();
        
        // 访问属性:对象名.属性名
        student1.name = "张三";
        student1.age = 20;
        student1.major = "计算机科学";
        student1.score = 85.5;
        
        // 调用方法:对象名.方法名()
        student1.introduce();
        student1.study();
        student1.takeExam("Java", 92.0);
        
        // 创建多个对象
        Student student2 = new Student();
        student2.name = "李四";
        student2.age = 21;
        student2.major = "软件工程";
        student2.introduce();
    }
}

对象内存分析

text
┌─────────────────────────────────────────────────────────────────┐
│                      对象内存结构                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   栈内存                         堆内存                         │
│  ┌──────────────┐              ┌─────────────────────────┐     │
│  │   student1   │─────────────>│ name = "张三"           │     │
│  │  (引用地址)   │              │ age = 20               │     │
│  └──────────────┘              │ major = "计算机科学"     │     │
│                                │ score = 85.5           │     │
│  ┌──────────────┐              └─────────────────────────┘     │
│  │   student2   │─────────────>│ name = "李四"           │     │
│  │  (引用地址)   │              │ age = 21               │     │
│  └──────────────┘              │ major = "软件工程"       │     │
│                                │ score = 0.0            │     │
│                                └─────────────────────────┘     │
└─────────────────────────────────────────────────────────────────┘

构造方法

构造方法用于创建对象时初始化对象的属性。

构造方法定义

java
public class Person {
    String name;
    int age;
    String gender;
    
    // 无参构造方法
    public Person() {
        System.out.println("无参构造方法被调用");
    }
    
    // 带参构造方法
    public Person(String name, int age) {
        this.name = name;  // this 指当前对象
        this.age = age;
        System.out.println("两参构造方法被调用");
    }
    
    // 全参构造方法
    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        System.out.println("全参构造方法被调用");
    }
    
    public void show() {
        System.out.println("姓名:" + name + ",年龄:" + age + ",性别:" + gender);
    }
}

构造方法使用

java
public class ConstructorDemo {
    public static void main(String[] args) {
        // 使用无参构造
        Person p1 = new Person();
        p1.name = "张三";
        p1.age = 25;
        p1.show();
        
        // 使用两参构造
        Person p2 = new Person("李四", 30);
        p2.show();
        
        // 使用全参构造
        Person p3 = new Person("王五", 28, "男");
        p3.show();
    }
}

构造方法注意事项

java
public class ConstructorNote {
    public static void main(String[] args) {
        // 1. 如果没有定义构造方法,系统提供默认无参构造
        // 2. 如果定义了有参构造,系统不再提供无参构造
        // 3. 构造方法可以重载
        // 4. 构造方法没有返回值,连 void 都没有
    }
}

class Book {
    String title;
    double price;
    
    // 构造方法重载
    public Book() {
        // 调用另一个构造方法(必须放在第一行)
        this("未命名", 0.0);
    }
    
    public Book(String title) {
        this(title, 0.0);
    }
    
    public Book(String title, double price) {
        this.title = title;
        this.price = price;
    }
}

封装

封装是隐藏对象的属性和实现细节,仅对外提供公共访问方式。

封装实现

java
public class BankAccount {
    // 私有属性:外部无法直接访问
    private String accountNumber;  // 账号
    private String owner;          // 户主
    private double balance;        // 余额
    
    // 无参构造
    public BankAccount() {
    }
    
    // 全参构造
    public BankAccount(String accountNumber, String owner, double balance) {
        this.accountNumber = accountNumber;
        this.owner = owner;
        this.balance = balance;
    }
    
    // 公共的 getter 方法:获取属性值
    public String getAccountNumber() {
        return accountNumber;
    }
    
    public String getOwner() {
        return owner;
    }
    
    public double getBalance() {
        return balance;
    }
    
    // 公共的 setter 方法:设置属性值
    public void setAccountNumber(String accountNumber) {
        this.accountNumber = accountNumber;
    }
    
    public void setOwner(String owner) {
        this.owner = owner;
    }
    
    // 余额设置需要验证
    public void setBalance(double balance) {
        if (balance >= 0) {
            this.balance = balance;
        } else {
            System.out.println("余额不能为负数");
        }
    }
    
    // 存款方法
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("存款成功,当前余额:" + balance);
        } else {
            System.out.println("存款金额必须大于0");
        }
    }
    
    // 取款方法
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("取款成功,当前余额:" + balance);
        } else {
            System.out.println("取款失败,余额不足或金额无效");
        }
    }
    
    // 显示账户信息
    public void showInfo() {
        System.out.println("账号:" + accountNumber);
        System.out.println("户主:" + owner);
        System.out.println("余额:" + balance);
    }
}

封装使用

java
public class EncapsulationDemo {
    public static void main(String[] args) {
        BankAccount account = new BankAccount("6222000012345678", "张三", 10000);
        
        // 通过 getter 获取属性
        System.out.println("户主:" + account.getOwner());
        System.out.println("余额:" + account.getBalance());
        
        // 通过方法操作数据
        account.deposit(5000);
        account.withdraw(3000);
        
        // 不能直接访问私有属性
        // account.balance = -100;  // 编译错误
        
        // 通过 setter 设置属性(有验证)
        account.setBalance(-100);  // 输出:余额不能为负数
    }
}

访问修饰符

text
┌─────────────────────────────────────────────────────────────────┐
│                      访问修饰符权限                              │
├─────────────────────────────────────────────────────────────────┤
│   修饰符    │  同一类  │  同一包  │  子类  │  其他包            │
├─────────────────────────────────────────────────────────────────┤
│   public    │   ✓     │    ✓     │   ✓    │    ✓              │
│   protected │   ✓     │    ✓     │   ✓    │    ✗              │
│   默认      │   ✓     │    ✓     │   ✗    │    ✗              │
│   private   │   ✓     │    ✗     │   ✗    │    ✗              │
└─────────────────────────────────────────────────────────────────┘
java
public class AccessModifier {
    public int publicVar = 1;        // 公共:任何地方可访问
    protected int protectedVar = 2;  // 受保护:同类、同包、子类可访问
    int defaultVar = 3;              // 默认:同类、同包可访问
    private int privateVar = 4;      // 私有:只有同类可访问
    
    public void show() {
        // 同一类中都可以访问
        System.out.println(publicVar);
        System.out.println(protectedVar);
        System.out.println(defaultVar);
        System.out.println(privateVar);
    }
}

this 关键字

this 关键字代表当前对象的引用。

java
public class ThisKeyword {
    private String name;
    private int age;
    
    // 1. 区分成员变量和局部变量
    public ThisKeyword(String name, int age) {
        this.name = name;  // this.name 是成员变量
        this.age = age;    // name 是参数
    }
    
    // 2. 调用本类的其他构造方法
    public ThisKeyword() {
        this("未知", 0);  // 必须放在第一行
    }
    
    public ThisKeyword(String name) {
        this(name, 0);
    }
    
    // 3. 调用本类的方法
    public void method1() {
        System.out.println("method1");
    }
    
    public void method2() {
        this.method1();  // 调用本类的 method1
        System.out.println("method2");
    }
    
    // 4. 返回当前对象
    public ThisKeyword getSelf() {
        return this;  // 返回当前对象
    }
    
    // 5. 作为参数传递
    public void print(ThisKeyword obj) {
        System.out.println(obj.name);
    }
    
    public void show() {
        print(this);  // 将当前对象作为参数传递
    }
}

static 关键字

static 关键字用于声明静态成员,属于类而不是对象。

静态变量

java
public class StaticVariable {
    // 实例变量:每个对象独立拥有
    String name;
    
    // 静态变量:所有对象共享
    static int count = 0;  // 计数器
    
    public StaticVariable(String name) {
        this.name = name;
        count++;  // 每创建一个对象,计数器加1
    }
    
    public static void main(String[] args) {
        StaticVariable s1 = new StaticVariable("张三");
        System.out.println("创建对象数:" + StaticVariable.count);  // 1
        
        StaticVariable s2 = new StaticVariable("李四");
        System.out.println("创建对象数:" + StaticVariable.count);  // 2
        
        StaticVariable s3 = new StaticVariable("王五");
        System.out.println("创建对象数:" + StaticVariable.count);  // 3
        
        // 静态变量可以通过类名访问(推荐)
        // 也可以通过对象访问(不推荐)
        System.out.println(s1.count);  // 3
        System.out.println(s2.count);  // 3
    }
}

静态方法

java
public class StaticMethod {
    // 实例变量
    String name = "张三";
    
    // 静态变量
    static String school = "清华大学";
    
    // 实例方法:可以访问实例变量和静态变量
    public void instanceMethod() {
        System.out.println(name);        // 可以访问实例变量
        System.out.println(school);      // 可以访问静态变量
    }
    
    // 静态方法:只能访问静态变量和静态方法
    public static void staticMethod() {
        // System.out.println(name);    // 编译错误:不能访问实例变量
        System.out.println(school);      // 可以访问静态变量
        
        // instanceMethod();            // 编译错误:不能调用实例方法
        staticMethod2();                // 可以调用静态方法
    }
    
    public static void staticMethod2() {
        System.out.println("静态方法2");
    }
    
    public static void main(String[] args) {
        // 静态方法通过类名调用(推荐)
        StaticMethod.staticMethod();
        
        // 也可以通过对象调用(不推荐)
        StaticMethod obj = new StaticMethod();
        obj.staticMethod();
    }
}

静态代码块

java
public class StaticBlock {
    static String name;
    static int age;
    
    // 静态代码块:类加载时执行,只执行一次
    static {
        System.out.println("静态代码块执行");
        name = "张三";
        age = 25;
    }
    
    // 构造代码块:每次创建对象时执行
    {
        System.out.println("构造代码块执行");
    }
    
    public StaticBlock() {
        System.out.println("构造方法执行");
    }
    
    public static void main(String[] args) {
        System.out.println("main方法开始");
        
        // 类加载时,静态代码块先执行
        new StaticBlock();
        new StaticBlock();
        
        // 输出顺序:
        // 静态代码块执行
        // main方法开始
        // 构造代码块执行
        // 构造方法执行
        // 构造代码块执行
        // 构造方法执行
    }
}

静态导入

java
// 静态导入:导入类的静态成员
import static java.lang.Math.PI;
import static java.lang.Math.sqrt;
import static java.util.Arrays.sort;

public class StaticImport {
    public static void main(String[] args) {
        // 直接使用静态成员,无需类名前缀
        System.out.println("PI = " + PI);
        System.out.println("sqrt(16) = " + sqrt(16));
        
        int[] arr = {3, 1, 2};
        sort(arr);  // 直接使用 sort 方法
        System.out.println(java.util.Arrays.toString(arr));
    }
}

代码块

java
public class CodeBlock {
    static int staticVar;
    int instanceVar;
    
    // 静态代码块:类加载时执行
    static {
        staticVar = 100;
        System.out.println("1. 静态代码块");
    }
    
    // 构造代码块:每次创建对象时执行,在构造方法之前
    {
        instanceVar = 200;
        System.out.println("2. 构造代码块");
    }
    
    // 构造方法
    public CodeBlock() {
        System.out.println("3. 构造方法");
    }
    
    public static void main(String[] args) {
        System.out.println("创建第一个对象:");
        new CodeBlock();
        
        System.out.println("\n创建第二个对象:");
        new CodeBlock();
        
        // 执行顺序:
        // 1. 静态代码块(只执行一次)
        // 2. 构造代码块
        // 3. 构造方法
    }
}

小结

本章我们学习了:

  • 类与对象:类是模板,对象是实例
  • 构造方法:用于初始化对象
  • 封装:隐藏实现细节,提供公共访问方式
  • this 关键字:代表当前对象
  • static 关键字:静态成员属于类
  • 代码块:静态代码块、构造代码块

下一章,我们将学习 面向对象进阶,了解继承、多态、抽象类和接口。