Java 对象与类
Java - 对象与类
Section titled “Java - 对象与类”Java 本质上是一种面向对象编程(OOP)语言。OOP 基于现实世界的对象来建模软件设计。Java 支持的关键 OOP 概念包括:
- 封装(Encapsulation): 将数据(字段)和操作数据的方法捆绑在一个单元(类)中,并控制对内部状态的访问。
- 继承(Inheritance): 允许一个新类(子类)继承现有类(超类)的属性和方法,促进代码重用。
- 多态(Polymorphism): 使对象能够呈现多种形式;通常允许将子类对象视为其超类的对象,并通过重写方法实现特定行为。
- 抽象(Abstraction): 隐藏复杂的实现细节,只暴露对象或系统的基本功能。
本章重点介绍 Java 中 OOP 的构建块:类(Classes)和对象(Objects)。
- 类(Class): 用于创建对象的蓝图或模板。它定义了该类的所有对象将拥有的共同属性(字段或特性)和行为(方法)。例如:一个
Car类定义了color、make、model等属性以及startEngine()、accelerate()、brake()等行为。 - 对象(Object): 类的一个实例。它代表从类蓝图创建的特定实体,拥有自己的状态(字段的具体值)。例如:
myBlueToyotaCamry是Car类的一个对象(一个实例),其color设置为“blue”,make设置为“Toyota”,model设置为“Camry”。
Java 中的对象
Section titled “Java 中的对象”思考现实世界中的对象:您的手机、一张桌子、一只宠物。每一个都有:
- 状态(State): 特性或属性(例如,一只狗的名字、品种、颜色、年龄)。
- 行为(Behavior): 它可以执行的动作(例如,一只狗可以叫唤、摇尾巴、吃东西、睡觉)。
Java 中的软件对象反映了这一点。它们的状态存储在字段(fields)(也称为实例变量)中,它们的行为通过**方法(methods)**实现。
方法操作对象的内部状态(其字段),并且是对象之间相互交互的主要方式。
Java 中的类
Section titled “Java 中的类”类是蓝图。它定义了从它创建的所有对象将是什么样子以及它们将如何行为。
基本类结构:
// 访问修饰符 class 类名 {//// // 字段(实例变量) - 定义状态// 数据类型 字段名1;// 数据类型 字段名2;// // ...//// // 构造方法 - 创建对象的特殊方法// 类名(参数) {// // 初始化代码// }//// // 方法 - 定义行为// 返回值类型 方法名1(参数) {// // 方法体(代码)// }// // ...//}示例:一个简单的 Dog 类:
public class Dog { // 字段(实例变量) String breed; int age; String color; String name;
// 构造方法 public Dog(String dogName, String dogBreed, int dogAge, String dogColor) { // 'this' 关键字指向当前正在创建的对象 this.name = dogName; this.breed = dogBreed; this.age = dogAge; this.color = dogColor; System.out.println("创建了 Dog 对象: " + this.name); }
// 方法(行为) void bark() { System.out.println(name + " 说: 汪!"); }
void celebrateBirthday() { this.age++; // 增加这个特定 Dog 对象的年龄 System.out.println("生日快乐," + name + "!你现在 " + age + " 岁了。"); }}类内部的变量类型:
- 实例变量(Fields): 在类中声明,但在任何方法外部。类的每个对象(实例)都有这些变量的自己的副本。它们代表对象的状态(例如
Dog类中的breed、age、color、name)。 - 局部变量(Local Variables): 在方法、构造方法或块中声明。它们只在代码块执行期间存在,不是对象状态的一部分。
- 类变量(静态字段,Static Fields): 使用
static关键字声明。静态变量只有一个副本,由类的所有对象共享。常用于常量或计数器(例如static final int MAX_SPEED = 100;或static int dogCount = 0;)。
构造方法是用于初始化新对象的特殊方法。它们的名称与类名相同,没有返回类型(甚至不是 void)。
- 每个类至少有一个构造方法。
- 如果您没有显式定义任何构造方法,Java 编译器会提供一个默认的无参构造方法(例如
public Dog() {})。 - 如果您定义了任何构造方法(就像我们的
Dog示例中那样),默认的无参构造方法将不会自动提供。 - 构造方法在使用
new关键字创建对象时被调用。 - 一个类可以有多个参数列表不同的构造方法(构造方法重载)。
带有多个构造方法的示例:
public class Rectangle { double width; double height;
// 构造方法 1: 无参数 (创建一个 1x1 的矩形) public Rectangle() { this.width = 1.0; this.height = 1.0; }
// 构造方法 2: 接受宽度和高度 public Rectangle(double w, double h) { this.width = w; this.height = h; }
// 构造方法 3: 接受一个值用于正方形 public Rectangle(double side) { this.width = side; this.height = side; }
// 计算面积的方法 public double getArea() { return this.width * this.height; }}创建对象(实例化)
Section titled “创建对象(实例化)”创建对象通常包含三个步骤,这些步骤通常合并在一个语句中:
- 声明(Declaration): 声明一个类类型的变量(
Dog myDog;)。 - 实例化(Instantiation): 使用
new关键字为对象分配内存(new)。 - 初始化(Initialization): 调用构造方法设置对象的初始状态(
Dog(“Buddy”, …))。
示例:
// 声明、实例化和初始化合并Dog myDog = new Dog("Buddy", "Golden Retriever", 3, "Golden");Rectangle square = new Rectangle(5.0); // 调用第三个构造方法访问实例变量和方法
Section titled “访问实例变量和方法”您可以使用点(.)运算符通过对象引用变量访问对象的实例变量(字段)和方法。
// 1. 创建一个对象ClassName objectReference = new ClassName(parameters);
// 2. 访问字段(通常不鼓励直接访问 public 字段,更倾向于使用方法)// value = objectReference.fieldName;// objectReference.fieldName = newValue;
// 3. 调用方法// objectReference.methodName(arguments);使用 Dog 类的示例:
public class DogPark { public static void main(String[] args) { // 创建两个 Dog 对象 Dog dog1 = new Dog("Buddy", "Golden Retriever", 3, "Golden"); Dog dog2 = new Dog("Lucy", "Poodle", 5, "White");
// 访问字段(此处直接访问,但通常通过 Getter/Setter 等方法完成) System.out.println(dog1.name + " 的年龄: " + dog1.age);
// 调用方法 dog1.bark(); // 输出: Buddy 说: 汪! dog2.bark(); // 输出: Lucy 说: 汪!
dog1.celebrateBirthday(); // 输出: 生日快乐,Buddy!你现在 4 岁了。 System.out.println(dog1.name + " 的新年龄: " + dog1.age); // 输出: Buddy 的新年龄: 4 }}封装和访问修饰符
Section titled “封装和访问修饰符”在 Java 中,为了强制实现封装,通常将字段声明为 private。这意味着它们只能通过类内部定义的方法(如 Getter 和 Setter 方法)进行访问或修改。这可以防止外部代码使对象处于无效状态。
带有 private 字段和 public 方法(Getter/Setter)的示例:
public class SecureBankAccount { private String accountNumber; private double balance;
public SecureBankAccount(String accNumber, double initialBalance) { this.accountNumber = accNumber; // 为余额添加验证 if (initialBalance >= 0) { this.balance = initialBalance; } else { this.balance = 0; System.err.println("初始余额不能为负数。设置为 0。"); } }
// 余额的 Getter 方法 (允许读取) public double getBalance() { return balance; }
// 账户号的 Getter 方法 public String getAccountNumber() { return accountNumber; }
// 存款方法 (允许受控修改) public void deposit(double amount) { if (amount > 0) { balance += amount; } else { System.err.println("存款金额必须为正数。"); } }
// 取款方法 (允许受控修改) public boolean withdraw(double amount) { if (amount > 0 && amount <= balance) { balance -= amount; return true; // 成功 } else { System.err.println("取款失败:无效金额或余额不足。"); return false; // 失败 } }}访问修饰符(public、private、protected、默认)控制类、字段和方法的可见性。它们对于封装和 API 设计至关重要。
源文件声明规则
Section titled “源文件声明规则”组织 Java 代码时请记住这些规则:
- 每个源文件(
.java文件)只能包含一个public类。 - 源文件的名称必须与其中包含的
public类的名称完全匹配(例如,Dog类必须位于名为Dog.java的文件中)。 - 一个源文件可以包含多个非
public(包私有)的类。 - 如果类属于某个包,则
package声明必须是文件中的第一条语句。 import语句(如果存在)必须出现在package语句(如果存在)和类声明之间。package和import语句适用于源文件中的所有类。
**包(Packages)**用于将相关的类和接口组织到命名空间中,防止命名冲突并改进代码结构(例如 java.util、com.mycompany.myapp.ui)。
**导入语句(Import statements)**允许您使用其他包中的类,而无需每次都指定它们的完全限定名(包名 + 类名)。例如:import java.util.ArrayList; 允许您使用 ArrayList 而不是 java.util.ArrayList。
简单案例研究:员工管理
Section titled “简单案例研究:员工管理”我们创建两个类:Employee(蓝图)和 EmployeeTest(用于创建和使用 Employee 对象)。
1. Employee.java:
package com.example.hr; // 包声明示例
import java.time.LocalDate;import java.time.Period;
public class Employee { // 使用 private 字段实现封装 private String name; private String designation; private double salary; private LocalDate hireDate;
// 构造方法 public Employee(String name, String designation, double salary, LocalDate hireDate) { this.name = name; this.designation = designation; this.salary = salary; // 考虑添加验证 this.hireDate = hireDate; }
// Getter 方法 public String getName() { return name; }
public String getDesignation() { return designation; }
public double getSalary() { return salary; }
public LocalDate getHireDate() { return hireDate; }
// Setter 方法 (可选,仅在允许修改时提供) public void setDesignation(String designation) { this.designation = designation; }
public void setSalary(double salary) { if (salary >= 0) { // 基本验证 this.salary = salary; } else { System.err.println("薪水不能为负数。"); } }
// 计算服务年限的方法 public int getYearsOfService() { return Period.between(hireDate, LocalDate.now()).getYears(); }
// 打印员工详情的方法 public void printEmployeeDetails() { System.out.println("---------------------------"); System.out.println("姓名: " + name); System.out.println("职位: " + designation); System.out.printf("薪水: $%.2f%n", salary); // 格式化输出 System.out.println("入职日期: " + hireDate); System.out.println("服务年限: " + getYearsOfService()); System.out.println("---------------------------"); }}2. EmployeeTest.java(与 Employee 类在同一包中或导入 Employee 类):
package com.example.hr; // 与 Employee 在同一包中
// 或者如果在不同包中:// import com.example.hr.Employee;
import java.time.LocalDate;import java.time.Month;
public class EmployeeTest {
public static void main(String[] args) { // 使用构造方法创建 Employee 对象 Employee empOne = new Employee("James Smith", "Senior Software Engineer", 95000.00, LocalDate.of(2019, Month.MARCH, 15)); Employee empTwo = new Employee("Mary Anne", "Software Engineer", 72000.00, LocalDate.of(2021, Month.JULY, 1));
// 使用方法与对象交互 System.out.println("初始员工详情:"); empOne.printEmployeeDetails(); empTwo.printEmployeeDetails();
// 使用 Setter 方法修改对象 System.out.println("\n晋升 " + empTwo.getName() + "..."); empTwo.setDesignation("Senior Software Engineer"); empTwo.setSalary(90000.00);
System.out.println("\n更新后的员工详情:"); empOne.printEmployeeDetails(); // 未改变 empTwo.printEmployeeDetails(); // 显示晋升后的信息 }}编译和运行(假设文件位于正确的包结构中):
# 导航到包含 'com' 文件夹的基础目录cd path/to/your/project/src # 或类似的基础路径
# 编译两个 Java 文件 (使用 -d 指定输出目录)mkdir ../bin # 创建一个目录用于存放编译后的类文件 (可选但推荐的做法)javac -d ../bin com/example/hr/Employee.java com/example/hr/EmployeeTest.java
# 运行 EmployeeTest 类 (指定 classpath)java -cp ../bin com.example.hr.EmployeeTest预期输出将显示两名员工的详情,接着是 Mary Anne 晋升后的更新详情。
接下来是什么?
Section titled “接下来是什么?”理解类和对象是基础。接下来的章节将深入探讨相关的概念,如继承、多态以及 Java 中的基本数据类型。