0
点赞
收藏
分享

微信扫一扫

Java 对象和类全面教程:从基础到进阶

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

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

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

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

2. 类(Class)的概念

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

2.1 定义一个简单的类

java// Person.java
 public 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));        // 输出: 8
         System.out.println(calc.add(5, 3, 2));     // 输出: 10
         System.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方法
     @Override
     public 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
     @Override
     public 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)); // true
         System.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方法
     @Override
     public Object clone() throws CloneNotSupportedException {
         return super.clone();
     }
     
     // getter和setter方法...
     
     @Override
     public 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;
     }
     
     // 深拷贝实现
     @Override
     public Object clone() throws CloneNotSupportedException {
         Person cloned = (Person) super.clone();
         cloned.address = (Address) address.clone(); // 克隆address对象
         return cloned;
     }
     
     @Override
     public 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.0
         
         Point 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方法
     @Override
     public 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)的新特性

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

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

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

举报

相关推荐

JAVA基础语法:类和对象

0 条评论