Java面向对象编程精要:类与对象
Java 面向对象编程基础:类、对象与封装
Java 的核心编程范式之一是面向对象编程(Object-Oriented Programming, OOP)。它将现实世界中的事物抽象为“对象”,并通过对象之间的交互来构建程序。理解 类(Class)、对象(Object) 和 封装(Encapsulation) 是掌握 Java OOP 的基石。本文将详细介绍这些概念并结合代码示例进行说明。
一、面向对象思想
面向对象是一种解决问题的思维方式。它认为世界是由对象组成的,程序关注的是对象本身及其属性(状态)、行为(功能),以及对象之间的交互。这与 面向过程 注重解决问题的具体步骤形成对比。
-
面向过程:关注“如何做”。例如洗衣服,需要详细描述每一步:接水、浸泡、搓洗、漂洗、拧干、晾晒。
-
面向对象:关注“谁来做”。例如洗衣服,涉及几个对象:“脏衣服”、“洗衣机”、“洗衣粉”。程序关注的是这些对象各自的状态(衣服的脏污程度、洗衣机的模式、洗衣粉的量)和行为(洗衣机有“启动”、“选择模式”等功能,洗衣粉有“溶解去污”的功能),以及它们如何交互(人把衣服和洗衣粉放进洗衣机,启动洗衣机)。
两者各有适用场景,OOP 的优势在于能更好地模拟现实世界,提高代码的可维护性、复用性和可扩展性。
二、类(Class):对象的蓝图
1. 定义
类 是对具有相同属性和行为的一组对象的 抽象描述。它定义了这类对象共有的 属性(成员变量) 和 行为(成员方法)。类本身是抽象的,它充当了创建具体对象的 模板 或 蓝图。
例如,我们可以定义一个 Person 类来描述“人”这个概念:
-
属性(成员变量):
name(姓名)、age(年龄)。 -
行为(成员方法):
introduce()(自我介绍)、haveBirthday()(过生日)。
2. 类的声明语法
Java
public class ClassName {
// 成员变量 (属性)
dataType variableName1;
dataType variableName2;
// 构造方法 (用于创建对象)
public ClassName(parameters) { ... }
// 成员方法 (行为)
returnType methodName1(parameters) { ... }
returnType methodName2(parameters) { ... }
}
3. 代码示例:定义一个 Person 类
Java
public class Person {
// 成员变量 (属性)
private String name; // 使用 private 封装,后面会解释
private int age;
// 构造方法 1:无参构造
public Person() {
this.name = "Unknown";
this.age = 0;
}
// 构造方法 2:带参数构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法:自我介绍
public void introduce() {
System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");
}
// 成员方法:过生日
public void haveBirthday() {
age++; // 年龄增加一岁
System.out.println("Happy Birthday! Now I'm " + age);
}
// Getter 方法:获取姓名 (封装的一部分)
public String getName() {
return name;
}
// Setter 方法:设置姓名 (封装的一部分)
public void setName(String name) {
this.name = name;
}
// Getter 方法:获取年龄
public int getAge() {
return age;
}
// Setter 方法:设置年龄 (可加入校验逻辑)
public void setAge(int age) {
if (age >= 0) { // 简单的校验,年龄不能为负
this.age = age;
} else {
System.out.println("Invalid age! Age cannot be negative.");
}
}
}
解释:
-
private String name;和private int age;:声明了两个私有成员变量,代表人的姓名和年龄。 -
public Person()和public Person(String name, int age):这是两个构造方法。它们用于在创建Person对象时进行初始化。第一个无参构造给name和age赋予默认值;第二个带参构造允许在创建对象时指定初始姓名和年龄。 -
public void introduce()和public void haveBirthday():这是两个成员方法,定义了Person对象可以执行的行为:自我介绍和过生日。 -
public String getName()、public void setName(String name)、public int getAge()、public void setAge(int age):这些是用于访问和修改私有成员变量的 Getter 和 Setter 方法,是实现封装的关键。
三、对象(Object):类的实例
1. 定义
对象 是 类 的具体实例。类是抽象的蓝图,对象是根据这个蓝图创建出来的、存在于内存中的具体实体。每个对象都拥有类所定义的属性和方法,并且各自拥有独立的属性值。
例如,根据 Person 类,我们可以创建多个具体的“人”对象:
-
person1:name="Alice",age=25 -
person2:name="Bob",age=30
2. 创建对象(实例化)
使用 new 关键字后跟类的构造方法来创建对象。这个过程称为 实例化。
Java
ClassName objectName = new ClassName(arguments); // 根据构造方法选择参数
3. 使用对象
创建对象后,可以通过 点号 . 操作符来访问对象的成员变量(通常通过 Getter/Setter)和调用成员方法。
Java
objectName.methodName(arguments); // 调用方法
objectName.getVariableName(); // 通过 Getter 获取属性值
objectName.setVariableName(value); // 通过 Setter 设置属性值
4. 代码示例:创建并使用 Person 对象
Java
public class Main {
public static void main(String[] args) {
// 1. 使用无参构造创建 Person 对象 person1
Person person1 = new Person(); // name="Unknown", age=0
person1.introduce(); // 输出: Hello, my name is Unknown, I'm 0 years old.
// 2. 使用带参构造创建 Person 对象 person2
Person person2 = new Person("Alice", 25);
person2.introduce(); // 输出: Hello, my name is Alice, I'm 25 years old.
// 3. 使用 Setter 方法修改 person1 的属性
person1.setName("Bob");
person1.setAge(30);
person1.introduce(); // 输出: Hello, my name is Bob, I'm 30 years old.
// 4. 使用 Getter 方法获取 person2 的年龄
System.out.println(person2.getName() + "'s age is " + person2.getAge()); // 输出: Alice's age is 25
// 5. 调用行为方法
person2.haveBirthday(); // 输出: Happy Birthday! Now I'm 26
person2.introduce(); // 输出: Hello, my name is Alice, I'm 26 years old.
// 6. 尝试设置无效年龄 (通过 Setter 的校验)
person1.setAge(-5); // 输出: Invalid age! Age cannot be negative.
System.out.println(person1.getAge()); // 输出: 30 (保持不变)
}
}
解释:
-
Person person1 = new Person();:使用无参构造创建对象person1,其初始状态为name="Unknown",age=0。 -
Person person2 = new Person("Alice", 25);:使用带参构造创建对象person2,初始状态为name="Alice",age=25。 -
person1.setName("Bob")和person1.setAge(30):通过 Setter 方法修改person1的属性值。 -
person2.getName()和person2.getAge():通过 Getter 方法获取person2的属性值。 -
person2.haveBirthday():调用成员方法改变对象状态(age增加)。 -
person1.setAge(-5):尝试设置非法值,Setter 方法中的校验逻辑阻止了修改,并打印错误信息。
四、封装(Encapsulation):保护数据
1. 定义
封装 是面向对象编程的三大基本特性之一(另外两个是继承和多态)。封装的核心思想是将对象的 数据(属性) 和对数据的 操作(方法) 捆绑在一起,形成一个独立的单元(即类)。同时,隐藏对象内部的实现细节,只对外暴露有限的、可控的 接口(通常是公共方法) 来与对象进行交互。
2. 目的
-
提高安全性:防止外部代码随意、非法地修改对象的内部状态。例如,在
setAge方法中加入年龄不能为负的校验逻辑。 -
提高可维护性:内部实现细节的改变(如属性名改变、校验逻辑调整)不会影响依赖于对象公共接口的外部代码。
-
提高复用性:封装好的类可以被当作一个“黑盒”组件在其他地方复用,使用者只需关注接口。
-
简化复杂性:使用者无需了解对象内部的复杂逻辑,只需知道如何使用提供的公共方法。
3. 实现方式:访问权限修饰符
Java 使用 访问权限修饰符 来控制类、成员变量和方法的可见性:
-
private:私有的。仅在 当前类内部 可以访问。这是实现封装最常用的修饰符,用于修饰不希望被外部直接访问的成员变量(属性)。 -
(default)/ 无修饰符:默认的 / 包私有的。在 同一个包内 可以访问。 -
protected:受保护的。在 同一个包内 或 不同包的子类 中可以访问。 -
public:公共的。任何地方 都可以访问。通常用于修饰类本身、构造方法和希望外部调用的成员方法(如 Getter/Setter)。
4. 封装的核心实践:Getter 和 Setter
对私有(private)成员变量的访问和修改,通常通过公共的(public)Getter(获取值)和 Setter(设置值)方法来实现。这被称为 属性封装。
-
Getter:命名通常为
getXxx()(Xxx是属性名,首字母大写),没有参数,返回对应属性的值。 -
Setter:命名通常为
setXxx(),有一个与属性类型相同的参数(用于接收新值),返回类型为void。可以在 Setter 方法中加入必要的 数据校验逻辑。
回顾 Person 类的封装实现:
Java
public class Person {
private String name; // 私有属性
private int age; // 私有属性
// Getter for name
public String getName() {
return name; // 返回当前对象的 name 值
}
// Setter for name
public void setName(String name) {
this.name = name; // this.name 指当前对象的 name,= 右边的 name 是传入的参数
}
// Getter for age
public int getAge() {
return age;
}
// Setter for age (带校验)
public void setAge(int age) {
if (age >= 0) { // 校验逻辑:年龄必须 >= 0
this.age = age;
} else {
System.out.println("Invalid age! Age cannot be negative.");
}
}
// ... 其他方法省略 ...
}
关键点:
-
属性
name和age被声明为private,外部代码无法直接访问person.name或person.age。 -
外部代码只能通过
getName()、setName(String name)、getAge()、setAge(int age)这些公共方法来读取或修改属性值。 -
在
setAge(int age)方法中,加入了数据校验逻辑(age >= 0),确保了数据的有效性。这是封装带来的安全性的直接体现。
五、总结
-
类(Class):是对象的抽象模板,定义了对象共有的属性(成员变量)和行为(成员方法)。
-
对象(Object):是类的具体实例,拥有类定义的属性和方法,每个对象在内存中独立存在。
-
封装(Encapsulation):是 OOP 的核心特性之一,通过将数据(属性)和操作数据的方法捆绑在一起,并隐藏内部实现细节(通常使用
private修饰属性),仅对外提供公共访问接口(Getter/Setter 方法),来提高代码的安全性、可维护性和复用性。
理解并熟练运用类、对象和封装,是编写高质量、可维护 Java 程序的基础。它奠定了后续学习继承、多态等其他 OOP 特性的基石。
更多推荐


所有评论(0)