对象和类是Java面向对象编程(OOP)的核心概念。本教程将详细介绍Java中类和对象的概念、创建和使用方法,并提供丰富的代码示例。

1. 面向对象编程(OOP)基础

在深入学习类和对象之前,先了解OOP的四个基本特性:

  1. 封装(Encapsulation):隐藏对象内部细节,只暴露必要的接口
  2. 继承(Inheritance):子类继承父类的属性和方法
  3. 多态(Polymorphism):同一操作作用于不同对象有不同的解释
  4. 抽象(Abstraction):提取关键特征而忽略非关键细节

2. 类(Class)的概念

类是创建对象的蓝图或模板,它定义了对象的属性和行为。

2.1 定义一个简单的类

java// Person.javapublic class Person {// 成员变量(属性)String name;int age;// 成员方法(行为)public void introduce() {System.out.println("你好,我叫" + name + ",今年" + age + "岁。");}}

关键点

  • 类名通常采用大驼峰命名法(每个单词首字母大写)
  • 成员变量定义对象的属性
  • 成员方法定义对象的行为

3. 对象(Object)的概念

对象是类的实例,具有类定义的状态和行为。

3.1 创建和使用对象

javapublic class Main {public static void main(String[] args) {// 创建对象Person person1 = new Person();// 访问对象属性并赋值person1.name = "张三";person1.age = 25;// 调用对象方法person1.introduce();// 创建第二个对象Person person2 = new Person();person2.name = "李四";person2.age = 30;person2.introduce();}}

输出结果:

你好,我叫张三,今年25岁。你好,我叫李四,今年30岁。

4. 构造方法(Constructor)

构造方法用于在创建对象时初始化对象。

4.1 定义构造方法

javapublic class Person {String name;int age;// 无参构造方法public Person() {this.name = "未知";this.age = 0;}// 带参构造方法public Person(String name, int age) {this.name = name;this.age = age;}public void introduce() {System.out.println("你好,我叫" + name + ",今年" + age + "岁。");}}

4.2 使用构造方法

javapublic class Main {public static void main(String[] args) {// 使用无参构造方法Person person1 = new Person();person1.introduce();// 使用带参构造方法Person person2 = new Person("王五", 28);person2.introduce();}}

输出结果:

你好,我叫未知,今年0岁。你好,我叫王五,今年28岁。

5. 方法详解

5.1 方法的基本结构

java访问修饰符 返回类型 方法名(参数列表) {// 方法体return 返回值; // 如果返回类型不是void}

5.2 方法重载(Overloading)

同一个类中可以有多个同名方法,但参数列表必须不同。

javapublic class Calculator {// 两个整数相加public int add(int a, int b) {return a + b;}// 三个整数相加public int add(int a, int b, int c) {return a + b + c;}// 两个双精度数相加public double add(double a, double b) {return a + b;}}public class Main {public static void main(String[] args) {Calculator calc = new Calculator();System.out.println(calc.add(5, 3));        // 输出: 8System.out.println(calc.add(5, 3, 2));     // 输出: 10System.out.println(calc.add(5.5, 3.2));    // 输出: 8.7}}

5.3 参数传递

Java中参数传递都是值传递:

javapublic class ParameterTest {// 基本类型参数传递public void changePrimitive(int value) {value = 100;}// 引用类型参数传递public void changeObject(StringBuilder builder) {builder.append(" World!");}public static void main(String[] args) {ParameterTest test = new ParameterTest();// 基本类型测试int num = 10;test.changePrimitive(num);System.out.println(num); // 输出: 10 (未改变)// 引用类型测试StringBuilder sb = new StringBuilder("Hello");test.changeObject(sb);System.out.println(sb); // 输出: Hello World! (改变了)}}

6. 封装和访问控制

6.1 访问修饰符

修饰符

类内

同一包内

子类

其他包

private

(默认/包级)

protected

public

6.2 实现封装

javapublic class BankAccount {// 私有成员变量private String accountNumber;private double balance;// 公有构造方法public BankAccount(String accountNumber, double initialBalance) {this.accountNumber = accountNumber;this.balance = initialBalance;}// 公有方法访问私有变量public double getBalance() {return balance;}// 存款方法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 class Main {public static void main(String[] args) {BankAccount account = new BankAccount("123456789", 1000);account.deposit(500);account.withdraw(200);// 尝试直接访问私有变量会编译错误// System.out.println(account.balance); // 错误// 必须通过公有方法访问System.out.println("当前余额: " + account.getBalance());}}

7. static关键字

7.1 静态变量

静态变量属于类,而不是某个对象。

javapublic class Employee {private String name;private static int nextId = 1;private int id;public Employee(String name) {this.name = name;this.id = nextId++;}public void printInfo() {System.out.println("员工ID: " + id + ", 姓名: " + name);}public static int getNextId() {return nextId;}}public class Main {public static void main(String[] args) {Employee emp1 = new Employee("张三");Employee emp2 = new Employee("李四");emp1.printInfo(); // 员工ID: 1, 姓名: 张三emp2.printInfo(); // 员工ID: 2, 姓名: 李四System.out.println("下一个员工ID: " + Employee.getNextId()); // 3}}

7.2 静态方法

静态方法属于类,可以直接通过类名调用。

javapublic class MathUtils {// 静态方法public static double circleArea(double radius) {return Math.PI * radius * radius;}// 实例方法public double rectangleArea(double length, double width) {return length * width;}}public class Main {public static void main(String[] args) {// 调用静态方法double area = MathUtils.circleArea(5.0);System.out.println("圆的面积: " + area);// 调用实例方法需要先创建对象MathUtils utils = new MathUtils();double rectArea = utils.rectangleArea(4.0, 6.0);System.out.println("矩形的面积: " + rectArea);}}

8. final关键字

8.1 final变量

final变量一旦赋值就不能再修改。

javapublic class FinalTest {final int MAX_VALUE = 100; // final实例变量static final double PI = 3.1415926; // final静态变量public void printValues() {// MAX_VALUE = 150; // 编译错误,不能修改final变量System.out.println("最大值: " + MAX_VALUE);System.out.println("圆周率: " + PI);}public static void main(String[] args) {FinalTest test = new FinalTest();test.printValues();}}

8.2 final方法

final方法不能被子类重写。

javapublic class Parent {public final void showMessage() {System.out.println("这是final方法,不能被重写");}}public class Child extends Parent {// 尝试重写final方法会导致编译错误/*public void showMessage() {System.out.println("尝试重写final方法");}*/}

8.3 final类

final类不能被继承。

javapublic final class FinalClass {public void display() {System.out.println("这是一个final类");}}// 尝试继承final类会导致编译错误/*public class SubClass extends FinalClass {}*/

9. 对象比较

9.1 equals()方法

默认的equals()方法(继承自Object类)比较的是对象引用,通常需要重写。

javapublic class Book {private String title;private String author;public Book(String title, String author) {this.title = title;this.author = author;}// 重写equals方法@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null || getClass() != obj.getClass()) return false;Book book = (Book) obj;return title.equals(book.title) && author.equals(book.author);}// 通常重写equals时也重写hashCode@Overridepublic int hashCode() {return Objects.hash(title, author);}}public class Main {public static void main(String[] args) {Book book1 = new Book("Java编程思想", "Bruce Eckel");Book book2 = new Book("Java编程思想", "Bruce Eckel");Book book3 = new Book("Effective Java", "Joshua Bloch");System.out.println(book1.equals(book2)); // trueSystem.out.println(book1.equals(book3)); // false}}

9.2 ==运算符

==比较的是对象引用是否相同,而不是内容。

javapublic class Main {public static void main(String[] args) {String s1 = new String("Hello");String s2 = new String("Hello");String s3 = s1;System.out.println(s1 == s2); // false,不同对象System.out.println(s1.equals(s2)); // true,内容相同System.out.println(s1 == s3); // true,同一对象}}

10. 对象克隆

10.1 实现Cloneable接口

javapublic class Address implements Cloneable {private String city;private String street;public Address(String city, String street) {this.city = city;this.street = street;}// 重写clone方法@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}// getter和setter方法...@Overridepublic String toString() {return city + "市" + street + "街";}}public class Person implements Cloneable {private String name;private int age;private Address address;public Person(String name, int age, Address address) {this.name = name;this.age = age;this.address = address;}// 深拷贝实现@Overridepublic Object clone() throws CloneNotSupportedException {Person cloned = (Person) super.clone();cloned.address = (Address) address.clone(); // 克隆address对象return cloned;}@Overridepublic String toString() {return "姓名: " + name + ", 年龄: " + age + ", 地址: " + address;}public static void main(String[] args) throws CloneNotSupportedException {Address address = new Address("北京", "朝阳");Person person1 = new Person("张三", 30, address);// 浅拷贝Person person2 = (Person) person1.clone();System.out.println("原始对象: " + person1);System.out.println("克隆对象: " + person2);// 修改克隆对象的地址person2.getAddress().setCity("上海");System.out.println("修改后原始对象: " + person1);System.out.println("修改后克隆对象: " + person2);}}

浅拷贝 vs 深拷贝

  • 浅拷贝:只复制基本类型和对象引用,不复制引用指向的对象
  • 深拷贝:复制所有对象,包括引用指向的对象

11. 记录类(Record Class) - Java 14+

Java 14引入了record类型,用于简化不可变数据类的定义。

java// 定义一个record类public record Point(int x, int y) {// 可以添加静态方法public static Point origin() {return new Point(0, 0);}// 可以添加实例方法public double distanceFromOrigin() {return Math.sqrt(x * x + y * y);}// 不能添加实例字段// 不能重写equals, hashCode, toString等方法(编译器会自动生成)}public class Main {public static void main(String[] args) {Point p1 = new Point(3, 4);System.out.println(p1); // Point[x=3, y=4]System.out.println(p1.x()); // 3 (自动生成的访问方法)System.out.println(p1.distanceFromOrigin()); // 5.0Point p2 = Point.origin();System.out.println(p2); // Point[x=0, y=0]}}

12. 最佳实践

  1. 始终使用访问修饰符:明确指定类成员的访问级别
  2. 封装内部实现:将成员变量设为private,通过方法访问
  3. 为类编写有意义的文档注释:使用Javadoc格式
  4. 实现equals()和hashCode()方法:如果对象需要比较或存储在集合中
  5. 考虑不可变性:对于不需要改变的对象,设计为不可变
  6. 合理使用final:在需要防止修改的地方使用final
  7. 避免过度设计:从简单开始,根据需要添加复杂性

13. 完整示例:银行账户管理系统

javaimport java.util.ArrayList;import java.util.List;// 银行账户类public class BankAccount {// 账户状态枚举public enum AccountStatus {ACTIVE, FROZEN, CLOSED}// 私有成员变量private final String accountNumber;private String accountHolder;private double balance;private AccountStatus status;private List<String> transactionHistory;// 构造方法public BankAccount(String accountNumber, String accountHolder, double initialBalance) {this.accountNumber = accountNumber;this.accountHolder = accountHolder;this.balance = initialBalance;this.status = AccountStatus.ACTIVE;this.transactionHistory = new ArrayList<>();logTransaction("账户创建,初始余额: " + initialBalance);}// 存款方法public void deposit(double amount) {if (status != AccountStatus.ACTIVE) {System.out.println("账户未激活,无法存款");return;}if (amount <= 0) {System.out.println("存款金额必须大于0");return;}balance += amount;logTransaction("存款: +" + amount);System.out.println("存款成功,当前余额: " + balance);}// 取款方法public void withdraw(double amount) {if (status != AccountStatus.ACTIVE) {System.out.println("账户未激活,无法取款");return;}if (amount <= 0) {System.out.println("取款金额必须大于0");return;}if (amount > balance) {System.out.println("余额不足");return;}balance -= amount;logTransaction("取款: -" + amount);System.out.println("取款成功,当前余额: " + balance);}// 转账方法public void transfer(BankAccount targetAccount, double amount) {if (this == targetAccount) {System.out.println("不能向同一账户转账");return;}this.withdraw(amount);targetAccount.deposit(amount);logTransaction("转账到账户 " + targetAccount.getAccountNumber() + ": -" + amount);}// 记录交易历史private void logTransaction(String description) {String entry = String.format("[%s] %s (余额: %.2f)", java.time.LocalDateTime.now(), description, balance);transactionHistory.add(entry);}// 显示交易历史public void displayTransactionHistory() {System.out.println("\n=== 账户交易历史 ===");System.out.println("账户号码: " + accountNumber);System.out.println("账户持有人: " + accountHolder);System.out.println("当前状态: " + status);for (String transaction : transactionHistory) {System.out.println(transaction);}System.out.println("==================\n");}// getter方法public String getAccountNumber() {return accountNumber;}public String getAccountHolder() {return accountHolder;}public double getBalance() {return balance;}public AccountStatus getStatus() {return status;}// setter方法(有限制)public void setAccountHolder(String accountHolder) {this.accountHolder = accountHolder;}public void setStatus(AccountStatus status) {this.status = status;logTransaction("账户状态变更为: " + status);}// 重写toString方法@Overridepublic String toString() {return String.format("BankAccount[number=%s, holder=%s, balance=%.2f, status=%s]",accountNumber, accountHolder, balance, status);}}// 主程序public class BankSystem {public static void main(String[] args) {// 创建账户BankAccount account1 = new BankAccount("1001", "张三", 1000);BankAccount account2 = new BankAccount("1002", "李四", 500);// 执行交易account1.deposit(200);account1.withdraw(150);account1.transfer(account2, 300);// 尝试无效操作account1.withdraw(2000); // 余额不足account1.transfer(account1, 100); // 同一账户转账// 冻结账户account1.setStatus(BankAccount.AccountStatus.FROZEN);account1.deposit(100); // 应该失败// 显示交易历史account1.displayTransactionHistory();account2.displayTransactionHistory();// 打印账户信息System.out.println(account1);System.out.println(account2);}}

总结

本教程全面介绍了Java中类和对象的核心概念:

  1. 类的定义和对象的创建
  2. 构造方法的使用
  3. 方法的定义和重载
  4. 封装和访问控制
  5. static和final关键字的使用
  6. 对象比较和克隆
  7. 记录类(Record)的新特性

通过学习这些概念和示例,您应该能够:

  • 设计并实现自己的类
  • 创建和使用对象
  • 理解对象之间的交互
  • 编写可维护、可扩展的面向对象代码

记住,面向对象编程的核心是设计出高内聚、低耦合的类,合理划分职责,并通过对象间的协作实现复杂功能。