一、回顾与本篇目标
前面六篇,你学会了 Java 的基础语法——变量、运算符、条件判断、循环、数组。你写的程序已经能处理数据、做判断、重复执行了。
但到目前为止,我们写的代码都是面向过程的:数据是数据,操作是操作,它们分散在各处。比如上一篇的学生成绩统计——学生姓名存在一个数组里,成绩存在另一个数组里,统计逻辑写在 main 方法中。如果项目越来越大,这种方式会让代码越来越难维护——数据和操作数据的方法散落在各处,同一个名字的函数可能冲突,修改一个功能要翻遍整个文件。
面向对象编程提供了一种更自然的代码组织方式。它把数据和操作数据的方法打包在一起,形成对象。比如一个“学生”对象,既有姓名、成绩这些数据,也有计算等级、打印信息这些方法。这种方式让代码更直观、更易维护、更可复用。
面向对象是 Java 最核心的编程思想。Java 中的一切代码都必须写在类里面——从第一篇的 HelloWorld 开始,你其实已经在用类了。这一篇,我们正式学习类和对象的完整概念。
本篇的目标:
- 理解什么是类、什么是对象
- 学会定义一个类——成员变量和成员方法
- 学会创建和使用对象
- 理解构造方法——对象创建时自动执行
- 理解
this关键字——指向当前对象
二、什么是类和对象——用现实生活来理解
在写代码之前,先用一个生活中的例子来理解这两个核心概念。
类是设计图纸,对象是造出来的实物
想象你要造一辆汽车。首先你需要一张设计图纸——上面画了汽车的结构、零件的尺寸、各个部件怎么连接。这张图纸不是真正的汽车,但它描述了汽车应该是什么样子。
有了图纸之后,你就可以按照图纸造出真正的汽车。一张图纸可以造很多辆车——它们结构相同,但颜色不同、车牌号不同、车主不同。
翻译成 Java 术语:
- 类:就是那张设计图纸。它定义了这种“东西”拥有哪些属性(比如颜色、品牌、速度)和哪些行为(比如加速、刹车、鸣笛)。
- 对象:就是按照图纸造出来的具体的一辆车。它是实际存在的,占用内存,你可以使用它。
- 属性:对应 Java 中的成员变量。
- 行为:对应 Java 中的成员方法。
在 Java 中,类就是数据类型,对象就是具体的值。就像 int 是类型,28 是值一样——Car 是类(类型),myCar 是对象(具体的值)。
三、定义你的第一个类
现在来定义一个简单的类——学生。一个学生有姓名、年龄、成绩这些属性,也有介绍自己、判断是否及格这些行为。
// Student.java —— 定义一个学生类
public class Student {
// 成员变量(属性)——描述"有什么"
String name; // 姓名
int age; // 年龄
double score; // 成绩
// 成员方法(行为)——描述"能做什么"
public void introduce() {
System.out.println("我叫" + name + ",今年" + age + "岁,成绩是" + score + "分。");
}
public boolean isPass() {
return score >= 60; // 成绩大于等于 60 就是及格
}
}
逐行解释:
public class Student:定义一个名为Student的类。public表示这个类是公开的,其他代码可以访问它。类名习惯用大驼峰命名法(每个单词首字母大写)。String name;:声明一个成员变量。这个变量属于Student类的每个对象。每个学生对象都有自己独立的name、age、score。public void introduce():定义一个成员方法。这个方法打印学生的自我介绍。void表示没有返回值。public boolean isPass():定义一个返回boolean值的方法,用来判断学生是否及格。- 在方法内部,
name、age、score直接写变量名就能访问——它们就是当前对象的属性。
四、创建对象并使用
类只是定义,不能直接使用。你需要用类来创建对象,然后使用这个对象。
// Main.java —— 使用 Student 类
public class Main {
public static void main(String[] args) {
// 创建对象:用 new 关键字
Student s1 = new Student();
Student s2 = new Student();
// 给对象的属性赋值
s1.name = "张三";
s1.age = 20;
s1.score = 85.5;
s2.name = "李四";
s2.age = 21;
s2.score = 92.0;
// 调用对象的方法
s1.introduce(); // 我叫张三,今年20岁,成绩是85.5分。
s2.introduce(); // 我叫李四,今年21岁,成绩是92.0分。
// 使用方法的返回值
System.out.println("张三及格了吗?" + s1.isPass()); // true
System.out.println("李四及格了吗?" + s2.isPass()); // true
}
}
逐行解释:
Student s1 = new Student();:用new关键字创建一个Student对象。类比:按照设计图纸造出一辆真实的汽车。这个对象现在存储在内存中,s1是一个引用,指向这个对象。s1.name = "张三";:通过点号.访问对象的属性并赋值。s1.introduce();:通过点号调用对象的方法。s1和s2是两个独立的对象,它们的属性互不影响——s1的 name 是张三,s2的 name 是李四。
默认值:如果创建对象后不给属性赋值,它们会有默认值——int 是 0,double 是 0.0,String 等引用类型是 null。
五、构造方法——对象创建时自动执行
上面的例子中,创建对象后需要逐行给属性赋值,有点麻烦。如果能在创建对象的同时就设置好属性的值,那该多好。
构造方法就是做这件事的。它是一个特殊的方法,在对象被创建时自动调用,通常用来给属性赋初值。
构造方法有两条规则:
- 方法名必须和类名完全一样。
- 没有返回类型(连
void都不写)。
// Student.java —— 带构造方法的版本
public class Student {
String name;
int age;
double score;
// 构造方法:创建对象时自动调用
public Student(String n, int a, double s) {
name = n;
age = a;
score = s;
System.out.println("一个学生对象被创建了!");
}
public void introduce() {
System.out.println("我叫" + name + ",今年" + age + "岁,成绩是" + score + "分。");
}
public boolean isPass() {
return score >= 60;
}
}
现在创建对象时可以直接传入参数:
public class Main {
public static void main(String[] args) {
// 创建对象的同时设置属性值
Student s1 = new Student("张三", 20, 85.5);
Student s2 = new Student("李四", 21, 92.0);
s1.introduce(); // 我叫张三,今年20岁,成绩是85.5分。
s2.introduce(); // 我叫李四,今年21岁,成绩是92.0分。
}
}
输出会先显示两行“一个学生对象被创建了!”,然后是两句自我介绍。构造方法在 new 执行时自动调用。
默认构造方法:如果你没有写任何构造方法,Java 会自动提供一个无参数的默认构造方法——所以之前的 new Student() 才能正常工作。但一旦你自己写了构造方法,默认构造方法就会消失。如果你还需要无参数创建对象的方式,需要手动写一个无参数的构造方法。
六、this 关键字——指向当前对象
上面构造方法中的参数名 n、a、s 不太直观——看名字不知道它们代表什么。更自然的写法是参数名和属性名一致。但这样就出现了一个问题:
public Student(String name, int age, double score) {
name = name; // 哪个是参数?哪个是属性?
age = age; // 这样写是把参数赋给了自己!
score = score; // 属性根本没有被赋值
}
这里 name = name 会把参数 name 的值赋给参数自己,对象的属性并没有被修改。这时需要用 this 关键字来区分——this 代表当前对象,this.name 代表当前对象的属性,name 代表参数。
// 正确的写法:用 this 区分属性和参数
public Student(String name, int age, double score) {
this.name = name; // this.name 是属性,name 是参数
this.age = age;
this.score = score;
}
this 的两大作用:
- 区分成员变量和局部变量:当参数名和属性名相同时,
this.属性名明确指向对象的属性。 - 代表当前对象本身:在方法内部,如果你需要把“这个对象”传给另一个方法,就用
this。
public class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void printInfo() {
System.out.println("姓名:" + this.name + ",年龄:" + this.age);
// this.name 和直接写 name 效果一样(当没有同名的局部变量时)
}
}
七、完整的示例——一个银行账户类
下面这个示例综合运用了类、对象、成员变量、成员方法、构造方法和 this:
// BankAccount.java —— 银行账户类
public class BankAccount {
// 成员变量(属性)
private String owner; // 账户持有人
private double balance; // 余额
// 构造方法
public BankAccount(String owner, double initialBalance) {
this.owner = owner;
this.balance = initialBalance;
System.out.println(owner + " 的账户已创建,初始余额:" + balance + " 元");
}
// 存钱
public void deposit(double amount) {
if (amount > 0) {
this.balance += amount;
System.out.println("存入 " + amount + " 元,当前余额:" + this.balance + " 元");
} else {
System.out.println("存款金额必须大于 0");
}
}
// 取钱
public void withdraw(double amount) {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount;
System.out.println("取出 " + amount + " 元,当前余额:" + this.balance + " 元");
} else if (amount > this.balance) {
System.out.println("余额不足!当前余额:" + this.balance + " 元");
} else {
System.out.println("取款金额必须大于 0");
}
}
// 查询余额
public double getBalance() {
return this.balance;
}
// 显示账户信息
public void showInfo() {
System.out.println("账户持有人:" + this.owner + ",余额:" + this.balance + " 元");
}
}
// Main.java —— 使用银行账户
public class Main {
public static void main(String[] args) {
// 创建两个账户
BankAccount account1 = new BankAccount("张三", 1000.0);
BankAccount account2 = new BankAccount("李四", 500.0);
System.out.println("\n===== 操作演示 =====");
// 张三存钱
account1.deposit(500.0);
// 张三取钱
account1.withdraw(200.0);
// 张三尝试取太多钱
account1.withdraw(2000.0);
// 李四操作
account2.deposit(300.0);
account2.withdraw(100.0);
System.out.println("\n===== 账户信息 =====");
account1.showInfo();
account2.showInfo();
}
}
输出:
张三 的账户已创建,初始余额:1000.0 元
李四 的账户已创建,初始余额:500.0 元
===== 操作演示 =====
存入 500.0 元,当前余额:1500.0 元
取出 200.0 元,当前余额:1300.0 元
余额不足!当前余额:1300.0 元
存入 300.0 元,当前余额:800.0 元
取出 100.0 元,当前余额:700.0 元
===== 账户信息 =====
账户持有人:张三,余额:1300.0 元
账户持有人:李四,余额:700.0 元
代码设计要点:
- 每个账户对象的数据(持有人、余额)是独立的——张三的存款取款不影响李四的账户。
- 方法内部做了数据验证——存款金额必须大于 0,取款不能超过余额。这保证了对象的数据始终有效。
private关键字让属性只能在这个类内部访问,外部代码不能直接修改balance,只能通过deposit()和withdraw()方法来操作。这就是封装的概念,下一篇会详细讲。
八、一个文件里放多个类
前面的例子中,我们把 Student 和 Main 放在两个 .java 文件里。实际上,一个 .java 文件里可以放多个类,但只能有一个 public 类,而且文件名必须和这个 public 类的名字一致。
// 文件名:BankDemo.java(必须和 public 类名一致)
public class BankDemo {
public static void main(String[] args) {
Account acc = new Account("张三", 1000.0);
acc.showInfo();
}
}
// 非 public 类可以放在同一个文件里
class Account {
private String owner;
private double balance;
public Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
}
public void showInfo() {
System.out.println(owner + " 的余额:" + balance);
}
}
编译 BankDemo.java 后,会生成两个 .class 文件:BankDemo.class 和 Account.class。
九、对象的内存模型——对象变量存的是地址
这是一个重要的理解。当你写 Student s1 = new Student(...); 时,变量 s1 并不是对象本身——它存储的是对象在内存中的地址(也叫引用)。真正的对象数据存在堆内存中。
类比:s1 是一张写着门牌号的纸条,真正的房子(对象)在门牌号指向的位置。把 s1 赋值给 s2,只是复制了纸条上的门牌号,并没有复制房子——两个纸条指向同一栋房子。
Student s1 = new Student("张三", 20, 85.5);
Student s2 = s1; // s2 和 s1 指向同一个对象
s2.name = "李四"; // 通过 s2 修改对象
System.out.println(s1.name); // 输出"李四"!因为 s1 和 s2 指向同一个对象
这和基本类型的行为不同——基本类型存的是值本身,赋值时会复制值:
int a = 10;
int b = a; // b 得到 a 的副本
b = 20;
System.out.println(a); // 10 —— a 不受 b 的影响
十、本篇动手练习
练习 1:定义一个图书类
新建 Book.java 和 BookDemo.java。定义 Book 类,包含属性:书名(title)、作者(author)、价格(price)、页数(pages)。写一个构造方法和一个 displayInfo() 方法打印所有信息。在 main 中创建两本不同的书并显示信息。
练习 2:定义一个矩形类
新建 Rectangle.java 和 RectangleDemo.java。定义 Rectangle 类,包含属性:宽(width)和高(height)。提供方法:getArea() 计算面积,getPerimeter() 计算周长,isSquare() 判断是否是正方形。创建几个矩形并测试。
练习 3:定义一个温度计类
新建 Thermometer.java 和 ThermometerDemo.java。定义 Thermometer 类,包含属性:摄氏温度(celsius)。提供方法:getFahrenheit() 返回华氏温度(公式:celsius × 9/5 + 32),getKelvin() 返回开尔文温度(公式:celsius + 273.15),isBoiling() 判断是否达到沸点(>= 100)。
练习 4:模拟一个简单计算器
新建 Calculator.java 和 CalculatorDemo.java。定义 Calculator 类,包含一个属性 result(当前结果,初始为 0)。提供方法:add(double n)(加)、subtract(double n)(减)、multiply(double n)(乘)、divide(double n)(除,注意除数为 0)、clear()(清零)、getResult()(获取当前结果)。模拟一系列计算操作。
十一、本篇小结
这一篇你进入了 Java 面向对象编程的世界:
- 类和对象:类是设计图纸(定义属性和方法),对象是按图纸造出来的实物(占用内存,实际可用)。类是一种数据类型,对象是具体的值。
- 成员变量:属于对象的属性。每个对象有自己的副本,互不影响。
- 成员方法:属于对象的行为。方法内部可以直接访问对象的属性。
- 构造方法:方法名和类名相同,没有返回类型。在
new创建对象时自动调用,通常用来初始化属性。如果你不写,Java 会提供一个无参数的默认构造方法。 this关键字:代表当前对象本身。当参数名和属性名相同时,用this.属性名来区分。- 对象变量存的是地址:把对象变量赋给另一个变量,两个变量指向同一个对象。这和基本类型的复制行为完全不同。
面向对象是 Java 编程的基石。下一篇,我们继续深入学习面向对象的三大特性——封装、继承、多态,这是写出高质量 Java 代码的关键。
下一篇预告
下一篇——《面向对象(下)——封装、继承与多态》:private 封装数据、extends 继承父类、方法重写、super 关键字、多态的含义和用法。这是面向对象编程的核心内容。
Java 零基础入门,每周更新。











暂无评论内容