Java学习--面向对象基础
文章摘要
面向对象是Java编程的核心思想之一。它不只是“创建一个类、new一个对象”这么简单,更重要的是学会把数据和操作数据的行为组织在同一个对象中,并通过构造器完成初始化,借助this明确当前对象,再利用封装性控制外部对数据的访问。
简单理解:类是对象的模板,对象是类的实例;属性保存对象的数据,方法描述对象能够执行的行为。
1.面向对象的基本概念
1.1面向对象到底是什么
面向对象强调:现实世界中的事物可以抽象为对象,对象既携带数据,也可以执行与这些数据相关的操作。程序不再只是零散变量和函数的堆积,而是围绕一个个对象组织起来。
例如,要保存学生“张三”的姓名和年龄,仅用一个基本数据类型无法同时描述String类型的姓名和int类型的年龄。此时可以定义Student类,把name和age组合成一个新的数据类型。
核型价值:确定了对象,就能找到与该对象相关的数据和行为,代码的结构会更清晰,也更接近人类理解现实事务的方法。
2.类、对象、属性和方法
2.1类是模板
类可以理解为一张模板或一份设计图,他规定对象应该具备哪些属性和方法。在项目中,通常会把用于描述数据的类放在entity包中,这类类常被成为实体类。
package entity; public class Student { public String name; // 属性:姓名 public int age; // 属性:年龄 public void run() { // 方法:行为 System.out.println("跑步"); } }2.2 对象是类的实例
对象是根据类创建出来的具体实例。类本身只定义结构,真正携带数据的是对象。创建对象使用new关键字。
Student s1 = new Student(); s1.name = "张三"; s1.age = 18; s1.run();上面s1是一个引用变量,它保存Student对象在内存中的地址。通过“对象名.属性名”可以读写属性,通过“对象名。方法名()”可以调用行为。
3.对象在内存中的执行过程
理解对象的内存过程,可以帮助我们解释为什么对象之间可能互不影响,也可以解释为什么多个变量指向同一个对象时会相互影响。
1. Java 源文件被编译为 .class 字节码,并在运行时加载。
2. main 方法进入方法调用栈。
3. 执行 new Student() 时,在堆内存中开辟一块空间。
4. 对象的成员变量先获得默认值,例如 name 为 null、age 为 0。
5. 堆内存地址返回给引用变量 s1。
6. 给 s1.name 和 s1.age 赋值,本质上是在修改堆中对象的数据。
7. 调用 s1.run() 时,根据对象类型找到 Student 类中的 run 方法并执行。
容易混淆的点:s1不是对象本身,它是保存对象地址的引用变量;真正的Student对象位于堆内存中。
4.类和对象的常见注意事项
- 类名一般采用大驼峰命名法,例如 Student、Teacher、SchoolInfo。
- 定义在类中、方法外的变量叫成员变量;定义在方法或代码块中的变量叫局部变量。
- 成员变量在创建对象时会自动获得默认值,局部变量则必须先赋值后使用。
- 一个 .java 文件可以定义多个类,但只能有一个 public 类,并且 public 类名必须与文件名一致。
- 不同 new 出来的对象通常互不影响;多个引用变量指向同一个对象时,修改对象会被所有引用看到。
| 数据类型 | 成员变量默认值 |
| byte、short、char、int、long | 0 |
| float、double | 0.0 |
| boolean | false |
| String、数组、其他引用类型 | null |
5.this关键字
this表示当前对象。成员方法运行时,一定是由某个对象发起调用的,this就指向这个正在调用方法的对象。
5.1 为什么需要this
当方法名或局部变量名与成员变量名相同时,Java会优先使用离自己更近的局部变量或参数。此时使用this.成员变量,可以明确访问的是当前对象的属性。
public class Student { private String name; private int age; public void setName(String name) { this.name = name; } }阅读方式:this.name = name 可以读成:把参数 name 的值,赋给当前对象的成员变量 name。
5.2 this还能调用成员变量
public void run(String name) { System.out.println(this.name); System.out.println("没事跑跑步"); } public void eat() { this.run("Jerry"); }在没有歧义时,this. 可以省略;但在实体类中显式写出 this,往往能让代码含义更清楚。
6.构造器:创建对象时完成初始化
构造器是创建对象时自动执行的特殊结构。它看起来像方法,但没有返回值类型,名称必须与类名完全一致。
public Student() { // 无参构造器 }6.1 无参构造器
如果类中没有显示编写任何构造器,Java会提供一个默认的无参构造器。因此Student s = new Student();可以正常执行。
6.2 有参构造器
有参构造器可以在创建对象的同时完成属性赋值。包含所有成员变量参数的构造器,通常称为全参构造器。
public Student(String name, int age) { this.name = name; this.age = age; } // 创建对象 Student s1 = new Student("张三", 18);重要规则:只要类中显式编写了有参构造器,Java 就不会再自动提供默认无参构造器。仍需无参创建对象时,必须手动补写无参构造器。
注意:在 IntelliJ IDEA 中,可以通过 Alt + Insert 或 Generate 菜单快速生成无参、部分参数或全参构造器。
7.封装:控制对向数据的访问
封装是Java面向对象的三大特性之一,另外两个是继承和多态。封装的核心不是简单地“把属性改成private”,而是隐藏不应该被外部直接操作的实现细节,并通过公开方法提供受控访问。
7.1 为什么不能把所有属性都设为public
如果属性使用 public 修饰,项目中的其他类可以随意修改它。比如学校名称原本固定为“北京大学”,但外部代码却可以把它改成其他内容,这会破坏对象数据的合理性。
7.2 标准封装步骤
1. 使用 private 修饰成员变量,让属性只能在当前类内部直接访问。
2. 根据需要提供 public 的 Getter 方法读取属性。
3. 根据需要提供 public 的 Setter 方法修改属性。
4. 在 Setter 中加入参数校验,可以阻止非法数据进入对象。
public class School { private String schoolName = "北京大学"; private String address; private String phone; public String getSchoolName() { return this.schoolName; } public String getAddress() { return this.address; } public void setAddress(String address) { this.address = address; } public String getPhone() { return this.phone; } public void setPhone(String phone) { this.phone = phone; } }上面的 schoolName 只提供 get 方法,因此外部只能读取,不能修改;address 和 phone 同时提供 get、set 方法,因此既可以获取也可以更新。
8.实体JavaBean
实体JavaBean可以理解为用于携带数据的实体类。对象负责保存和传递数据,而对象又必须依赖实体类来创建,因此实体类是Java程序中非常基础的组成部分。
8.1 初学者阶段常见的JavaBean写法
- 类通常放在 entity、model 或 domain 包中。
- 成员变量使用 private 修饰。
- 提供无参构造器。
- 根据需要提供全参构造器。
- 为属性提供 Getter 和 Setter。
- 类名能够清楚表达其所描述的数据,例如 Student、Product、Order。
public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }9.成员变量与局部变量的区别
| 比较项 | 成员变量 | 局部变量 |
|---|---|---|
| 定义位置 | 类中、方法外 | 方法、构造器或代码块内部 |
| 默认值 | 创建对象时自动获取默认值 | 没有默认值,使用前必须赋值 |
| 内存位置 | 通常随对象存放在堆中 | 通常随方法调用存在与栈帧中 |
| 作用域 | 可以被类中的成员方法访问 | 只能在所属的代码块中使用 |
生命周期 | 通常与对象共存亡 | 随方法调用产生,方法结束后消失 |
访问方式 | 常通过 this.变量名访问 | 直接使用变量名 |
记忆口诀:成员变量属于对象,局部变量属于一次方法执行。
10.综合示例:把知识点串起来
下面的示例同时使用了类、对象、成员变量、this、构造器和封装。它也是初学阶段最值得反复手写的一段代码。
public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name = name; this.setAge(age); } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public int getAge() { return this.age; } public void setAge(int age) { if (age >= 0 && age <= 150) { this.age = age; } } public void introduce() { System.out.println("我叫" + this.name + ",今年" + this.age + "岁。"); } }public class StudentTest { public static void main(String[] args) { Student s1 = new Student("张三", 18); s1.introduce(); Student s2 = new Student(); s2.setName("李四"); s2.setAge(20); s2.introduce(); } }这个版本比直接公开属性更安全:年龄只能通过 setAge 修改,而且能够在方法中检查范围。这正是封装的实际意义——让对象自己维护数据的有效性。
11.初学者常见错误
| 错误 | 原因和修正 |
| 构造器写了void | 构造器没有返回值类型,连 void 也不能写 |
有参构造器存在,却继续 new Student() | 显式写有参构造器后,默认无参构造器失效,需要手动补写 |
this.name = this.name | 左右两边都指成员变量,没有使用参数值;应写 this.name = name |
局部变量未赋值就使用 | 局部变量没有默认值,必须先初始化 |
所有属性都设为 public | 外部可以绕过校验随意修改,应使用 private 配合 Getter / Setter。 |
把类和对象混为一谈 | 类是模板,对象是根据模板创建的具体实例 |
以为两个引用就是两个对象 | 两个变量可能保存同一个地址,修改其中一个会影响另一个 |
12.总结
学习 Java 面向对象时,可以按照“类定义结构 → new 创建对象 → 构造器初始化 → this 指向当前对象 → private 隐藏属性 → Getter / Setter 控制访问”的顺序理解。掌握这一条主线后,后续学习继承、多态、接口、集合以及 Spring 项目中的实体类都会轻松很多。
最终知识链:类是模板,new 产生对象;对象在堆中保存数据;this 表示当前对象;构造器负责初始化;封装负责保护数据;JavaBean 负责携带和传递数据。
13.思考问题
1.为什么成员变量有默认值,而局部变量没有?
2.只写有参构造器后,为什么无参构造器会失效?
