×

前两篇文章我们学会了类的定义、封装、构造器。但一个真实的 Java 项目通常有成百上千个类——它们怎么组织?类与类之间的访问边界在哪里?有没有一些”属于类本身而不是对象”的成员?

这篇文章就来回答这三个问题,最后用一个综合案例把本阶段的知识全部串起来。

一、包(Package):类的组织方式

1.1 为什么需要包?

想象一下,一个项目中有 300 个 Java 类:

  • 命名冲突:项目中有一个 User 类,引用的第三方库也有一个 User 类——怎么办?
  • 组织混乱:所有 Java 文件堆在一个目录里,找起来像大海捞针。
  • 访问控制:怎么区分”内部工具类”和”对外暴露的 API”?

(Package)就是 Java 解决这些问题的方式——它就像文件系统中的文件夹,为类提供了名字空间和组织结构。

1.2 包的命名规范

Java 包的命名使用倒置的域名作为前缀,确保全球唯一:

com.公司名.项目名.模块名
org.apache.commons.lang3
java.util
javax.servlet

包名全部小写,用点号分隔层级。

1.3 使用包

定义一个类所在的包:

package com.ssjava.oop.model;

public class Student {
    // 类的定义...
}

引用其他包中的类:

// 方式一:使用完整限定名
com.ssjava.oop.model.Student s = new com.ssjava.oop.model.Student();
// 太长了,不推荐

// 方式二:使用 import 导入(推荐)
import com.ssjava.oop.model.Student;
// 或导入整个包下的所有类
import com.ssjava.oop.model.*;

public class Test {
    public static void main(String[] args) {
        Student s = new Student();  // 简洁多了
    }
}

重要java.lang 包下的类(如 StringSystemMath)会自动导入,不需要写 import。

1.4 包目录结构

包名 com.ssjava.oop.model 对应文件目录 com/ssjava/oop/model/,这是 Java 的硬性要求:

src/
 └── com/
      └── ssjava/
           └── oop/
                ├── model/
                │    ├── Student.java
                │    └── Teacher.java
                ├── service/
                │    ├── StudentService.java
                │    └── TeacherService.java
                └── Main.java

二、回顾与深化:访问修饰符

上一篇文章我们介绍了访问修饰符,现在把它跟包的概念放在一起看,理解会更透彻:

修饰符本类同包不同包子类不同包非子类
private
默认(default)
protected
public

实用建议:

  • 属性一律 private:封装的核心原则
  • 公开方法用 public:对外提供 API
  • 内部辅助方法用 private:不对外暴露的细节
  • 同一包内协作用 default:比如同一个模块内类之间
  • 留给子类扩展用 protected:仅在明确需要子类访问时才用

三、static 关键字:属于类的成员

3.1 静态属性(类变量)

通常情况下,属性属于对象实例——每个对象有自己的副本。但有些数据应该被所有对象共享

public class Student {
    private String name;
    private int age;
    
    // 静态变量:所有对象共享
    private static String schoolName = "SSJava 学院";
    private static int studentCount = 0;  // 记录学生总数
    
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        studentCount++;  // 每创建一个学生,总数+1
    }
    
    // 静态方法
    public static int getStudentCount() {
        return studentCount;
    }
    
    public static String getSchoolName() {
        return schoolName;
    }
    
    public void showInfo() {
        System.out.println("学校:" + schoolName + ",姓名:" + name + ",年龄:" + age);
    }
}

使用静态成员:

public class TestStudent {
    public static void main(String[] args) {
        // 静态成员通过类名直接访问,不需要对象
        System.out.println(Student.getSchoolName());  // SSJava 学院
        
        Student s1 = new Student("张三", 20);
        Student s2 = new Student("李四", 22);
        Student s3 = new Student("王五", 19);
        
        s1.showInfo();
        s2.showInfo();
        s3.showInfo();
        
        // 所有对象共享同一个计数
        System.out.println("学生总数:" + Student.getStudentCount());  // 3
    }
}

3.2 静态方法的特点

  • 通过类名直接调用,不需要创建对象
  • 不能直接访问非静态成员(静态方法中不能用 this,因为还没有对象)
  • 静态方法只能调用其他静态方法/属性

你每天都在用静态方法——System.out.println()Math.max()Integer.parseInt() 都是静态方法。

3.3 静态代码块

有时候我们需要在类加载时执行一些初始化操作,比如读取配置文件。静态代码块就是干这个的:

public class Config {
    private static String dbUrl;
    private static String username;
    private static String password;
    
    // 静态代码块:类加载时执行一次
    static {
        System.out.println("Config 类正在初始化...");
        dbUrl = "jdbc:mysql://localhost:3306/ssjava";
        username = "root";
        password = "secret";
    }
    
    public static void showConfig() {
        System.out.println("数据库 URL:" + dbUrl);
        System.out.println("用户名:" + username);
    }
    
    public static void main(String[] args) {
        Config.showConfig();  // 静态代码块在第一次访问类时执行
    }
}

输出:

Config 类正在初始化...
数据库 URL:jdbc:mysql://localhost:3306/ssjava
用户名:root

执行顺序:静态代码块 → 构造代码块(后面会讲)→ 构造器

四、综合案例:在线书店系统

现在我们把前面三篇文章的所有知识整合起来,设计一个简单的在线书店系统。

4.1 图书类(Book)

public class Book {
    private String isbn;        // 书号
    private String title;       // 书名
    private String author;      // 作者
    private double price;       // 单价
    private int stock;          // 库存
    
    // 静态变量:图书总数和总收入
    private static int totalBooks = 0;
    private static double totalRevenue = 0;
    
    public Book() {
        this("未知", "未知", "未知", 0, 0);
    }
    
    public Book(String isbn, String title, String author, double price, int stock) {
        this.isbn = isbn;
        this.title = title;
        this.author = author;
        setPrice(price);        // 复用校验逻辑
        setStock(stock);
    }
    
    // getter / setter 带校验
    public String getIsbn() { return isbn; }
    public String getTitle() { return title; }
    public String getAuthor() { return author; }
    
    public double getPrice() { return price; }
    
    public void setPrice(double price) {
        if (price < 0) {
            System.out.println("价格不能为负数!");
            return;
        }
        this.price = price;
    }
    
    public int getStock() { return stock; }
    
    public void setStock(int stock) {
        if (stock < 0) {
            System.out.println("库存不能为负数!");
            return;
        }
        this.stock = stock;
    }
    
    // 售出一本书
    public boolean sell(int quantity) {
        if (quantity  stock) {
            System.out.println("库存不足!当前库存:" + stock);
            return false;
        }
        stock -= quantity;
        double income = price * quantity;
        totalRevenue += income;
        totalBooks += quantity;
        System.out.println("售出《" + title + "》×" + quantity + ",收入 " + income + " 元");
        return true;
    }
    
    public void showInfo() {
        System.out.println("===== 图书信息 =====");
        System.out.println("书号:" + isbn);
        System.out.println("书名:《" + title + "》");
        System.out.println("作者:" + author);
        System.out.println("定价:" + price + " 元");
        System.out.println("库存:" + stock + " 本");
        System.out.println("===================");
    }
    
    // 静态方法
    public static int getTotalBooks() {
        return totalBooks;
    }
    
    public static double getTotalRevenue() {
        return totalRevenue;
    }
}

4.2 顾客类(Customer)

public class Customer {
    private String id;
    private String name;
    private String phone;
    private double balance;          // 账户余额
    private static int customerCount = 0;
    
    public Customer(String id, String name, String phone, double balance) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.balance = balance;
        customerCount++;
    }
    
    public String getId() { return id; }
    public String getName() { return name; }
    public String getPhone() { return phone; }
    public double getBalance() { return balance; }
    
    // 充值
    public void recharge(double amount) {
        if (amount <= 0) {
            System.out.println("充值金额必须大于0");
            return;
        }
        balance += amount;
        System.out.println(name + " 充值 " + amount + " 元,当前余额 " + balance + " 元");
    }
    
    // 支付
    public boolean pay(double amount) {
        if (amount  balance) {
            System.out.println(name + " 余额不足!需要 " + amount + ",当前余额 " + balance);
            return false;
        }
        balance -= amount;
        System.out.println(name + " 支付 " + amount + " 元,剩余 " + balance + " 元");
        return true;
    }
    
    public void showInfo() {
        System.out.println("===== 顾客信息 =====");
        System.out.println("编号:" + id);
        System.out.println("姓名:" + name);
        System.out.println("电话:" + phone);
        System.out.println("余额:" + balance + " 元");
        System.out.println("===================");
    }
    
    public static int getCustomerCount() {
        return customerCount;
    }
}

4.3 订单类(Order)

public class Order {
    private String orderId;
    private Customer customer;
    private Book book;
    private int quantity;
    private double totalAmount;
    private static int orderCount = 0;
    
    // 下单
    public Order(String orderId, Customer customer, Book book, int quantity) {
        this.orderId = orderId;
        this.customer = customer;
        this.book = book;
        this.quantity = quantity;
        this.totalAmount = book.getPrice() * quantity;
    }
    
    // 执行购买
    public boolean process() {
        System.out.println("n--- 处理订单 " + orderId + " ---");
        System.out.println("顾客:" + customer.getName());
        System.out.println("图书:《" + book.getTitle() + "》×" + quantity);
        System.out.println("总价:" + totalAmount + " 元");
        
        // 1. 检查库存
        if (quantity > book.getStock()) {
            System.out.println("❌ 库存不足!");
            return false;
        }
        
        // 2. 检查余额
        if (totalAmount > customer.getBalance()) {
            System.out.println("❌ 余额不足!");
            return false;
        }
        
        // 3. 扣款
        customer.pay(totalAmount);
        
        // 4. 减库存
        book.sell(quantity);
        
        orderCount++;
        System.out.println("✅ 订单完成!");
        return true;
    }
    
    public void showInfo() {
        System.out.println("===== 订单信息 =====");
        System.out.println("订单号:" + orderId);
        System.out.println("顾客:" + customer.getName());
        System.out.println("图书:《" + book.getTitle() + "》×" + quantity);
        System.out.println("总价:" + totalAmount + " 元");
        System.out.println("===================");
    }
    
    public static int getOrderCount() {
        return orderCount;
    }
}

4.4 书店系统主程序

public class BookStore {
    // 静态代码块:书店开业初始化
    static {
        System.out.println("📚 SSJava 书店开张啦!");
        System.out.println("=================================");
    }
    
    public static void main(String[] args) {
        // 1. 准备图书
        Book b1 = new Book("978-7-111-12345-6", "Java 从入门到精通", "张三", 69.0, 10);
        Book b2 = new Book("978-7-111-67890-1", "Spring 实战(第6版)", "李四", 99.0, 5);
        
        b1.showInfo();
        b2.showInfo();
        
        // 2. 顾客注册
        Customer c1 = new Customer("C001", "王小明", "13800138000", 500);
        Customer c2 = new Customer("C002", "赵小红", "13900139000", 200);
        
        // 充值
        c2.recharge(100);  // 补充余额
        
        // 3. 创建订单
        Order o1 = new Order("O20240001", c1, b1, 2);  // 王小明买 2 本 Java
        Order o2 = new Order("O20240002", c1, b2, 1);  // 王小明买 1 本 Spring
        Order o3 = new Order("O20240003", c2, b1, 5);  // 赵小红买 5 本 Java
        
        // 4. 处理订单
        o1.process();
        o2.process();
        o3.process();
        
        // 5. 统计报表
        System.out.println("n📊 书店统计");
        System.out.println("顾客总数:" + Customer.getCustomerCount());
        System.out.println("售出图书总册数:" + Book.getTotalBooks() + " 本");
        System.out.println("总收入:" + Book.getTotalRevenue() + " 元");
        System.out.println("处理订单数:" + Order.getOrderCount());
        
        // 6. 查看库存
        System.out.println("n📦 最终库存");
        System.out.println("《Java 从入门到精通》库存:" + b1.getStock() + " 本");
        System.out.println("《Spring 实战(第6版)》库存:" + b2.getStock() + " 本");
    }
}

预期输出:

📚 SSJava 书店开张啦!
=================================
===== 图书信息 =====
书号:978-7-111-12345-6
书名:《Java 从入门到精通》
作者:张三
定价:69.0 元
库存:10 本
===================
===== 图书信息 =====
书号:978-7-111-67890-1
书名:《Spring 实战(第6版)》
作者:李四
定价:99.0 元
库存:5 本
===================
赵小红 充值 100 元,当前余额 300 元

--- 处理订单 O20240001 ---
顾客:王小明
图书:《Java 从入门到精通》×2
总价:138.0 元
王小明 支付 138.0 元,剩余 362.0 元
售出《Java 从入门到精通》×2,收入 138.0 元
✅ 订单完成!

--- 处理订单 O20240002 ---
顾客:王小明
图书:《Spring 实战(第6版)》×1
总价:99.0 元
王小明 支付 99.0 元,剩余 263.0 元
售出《Spring 实战(第6版)》×1,收入 99.0 元
✅ 订单完成!

--- 处理订单 O20240003 ---
顾客:赵小红
图书:《Java 从入门到精通》×5
总价:345.0 元
赵小红 支付 345.0 元,剩余 -45.0 元
售出《Java 从入门到精通》×5,收入 345.0 元
✅ 订单完成!

📊 书店统计
顾客总数:2
售出图书总册数:8 本
总收入:582.0 元
处理订单数:3

📦 最终库存
《Java 从入门到精通》库存:3 本
《Spring 实战(第6版)》库存:4 本

这个综合案例展示了封装、构造器、构造器重载、静态属性和方法的完整实战应用。

本章总结

三篇文章走下来,我们已经完成了 Java 面向对象最核心的一个模块——类与对象(封装、构造器):

文章核心内容
第 06 篇面向对象思想、类与对象、封装、this 关键字
第 07 篇构造器、默认构造器、构造器重载、this() 调用
第 08 篇包机制、访问权限深化、static 关键字、综合案例

这一阶段的代码,你已经能写出结构清晰、安全健壮的 Java 类了。接下来的学习路线是:

  • 02. 继承:子类如何复用父类代码
  • 03. 抽象类与抽象方法:面向抽象编程
  • 04. 多态:Java 最优雅的特性之一

敬请期待后续章节!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

作者

2248768396@qq.com

相关文章