Java类与对象
Java类与对象(掌握面向对象的核心)
从C语言入门编程人,刚接触Java时一定会有个疑问:struct 已经能定义复合数据类型了,为什么Java还要提出 class、类与对象的概念?
实际上这是两种完全不同的编程思维范式。
c语言是面向过程语言,面向过程的核心是过程,也就是 “步骤、流程”。它把一个问题拆解成「先做什么、再做什么、最后做什么」,用一个个函数去实现每个步骤,最后按顺序调用函数完成任务。
在“面向对象程序设计(Object-Oriented Programming, OOP)里。面向对象的核心是对象,也就是 “实体、角色”。它先不着急想步骤,而是先分析:这件事里有哪些 “事物” 参与?每个事物有什么特征(属性)、能做什么事(行为)?把属性和行为打包成一个 “对象”,再让对象之间互相配合完成任务。
类与对象不是Java凭空创造的语法,而是面向对象思想最基础的载体——它把“数据”和“操作数据的行为”打包在一起,让编程从“一步步怎么做”,变成了“让谁来做”。
一、类:面向对象的“抽象模板”
1. 什么是类?
在面向对象的世界观里,一切皆对象,而类(Class)就是对同一类事物的共性抽象。
- 从语法角度:类是Java中自定义的引用数据类型,相当于我们自己定义了一种新的“数据类型”。
- 从设计角度:类是一张设计图纸,定义了一类事物拥有的属性(成员变量)和行为(成员方法)。
对比C语言的 struct 你会立刻明白差异:C的结构体只能定义数据,而Java的类可以同时包含“数据”和“处理数据的方法”,这就是最基础的封装思想。
举个例子:我们要描述“学生”这类事物,就可以定义一个 Student 类:
public class Student {
// 属性(成员变量):学生的共同特征
private String name; // 姓名
private int age; // 年龄
// 行为(成员方法):学生能做的事
public void study() {
System.out.println(name + "正在学习");
}
}
这里的 name 和 age 是所有学生都有的属性,study() 是学生都有的行为;Student 这个类,就定义了“学生”这个群体的统一规范。
二、对象:类的“具体实例”
1. 什么是对象?
类是抽象的模板,不能直接使用;对象(Object)就是根据类这个模板,创建出来的具体、真实的实例。(相当于印钞机和纸币的关系),更精确的说对象就是真实世界中的实体,对象与实体是一一对应的,也就是说现实世界中每一个实体都是一个对象,它是一种具体的概念。
- 类是“学生”这个概念,对象就是“名叫张三、今年18岁”的这个具体学生。
- 一个类可以创建无数个对象,每个对象的属性值可以不同,但都遵循类定义的结构。
在Java中,我们用 new 关键字创建对象:
public class Main {
public static void main(String[] args) {
// 创建Student对象,变量s是对象的引用
Student s = new Student();
}
}
2. 基本类型 vs 引用类型
这里要区分一个核心概念:Java的数据类型分为两类,这也是理解对象的关键:
| 类型 | 存储内容 | 存储位置 | 示例 |
|---|---|---|---|
| 基本数据类型 | 具体的数值 | 栈内存 | int a = 10; |
| 引用数据类型 | 对象的内存地址(引用) | 栈里存地址,对象本体在堆内存 | String str = "Hello"; Student s = new Student(); |
简单说:int a = 10 里,变量a和值10都在栈里;而 Student s 里,变量s只是一个“地址指针”存在栈中,真正的学生对象本体,存在堆内存里。
三、深入底层:对象的内存模型
很多人学不懂对象,是因为没搞懂栈(Stack)和堆(Heap)的分工。我们结合内存模型拆解 new Student() 的全过程。
1. 栈与堆的分工
- 栈内存(Stack):遵循“先入后出”的规则,存放方法的局部变量、方法调用的栈帧。方法执行结束,栈帧自动销毁,内存自动释放。
- 堆内存(Heap):存放所有new出来的对象本体,内存空间大,不会随方法结束自动销毁。
2. 对象创建的内存过程
当执行 Student s = new Student(); 时:
- JVM在堆内存中开辟一块空间,创建Student对象,给成员变量赋默认初始值(引用类型默认null,int默认0);
- 将这个对象的内存地址,赋值给栈内存中的变量
s; - 后续我们操作变量
s,本质是通过地址找到堆里的对象,这就是Java的**引用(Reference)**机制。
3. 和C语言的对比:自动垃圾回收(GC)
在C语言中,我们手动用 malloc 申请堆内存,用完必须手动 free 释放,否则就会出现内存泄漏。
而在Java中,你不需要手动释放内存——JVM的垃圾回收器(GC)会自动回收没有任何引用指向的堆对象。当一个对象没有任何栈变量指向它时,GC就会在合适的时机回收它的内存,彻底解放了程序员的内存管理负担。
四、对象的“出生”:构造方法
对象创建出来时,成员变量默认都是初始值(0、null等)。如果我们想在创建对象的同时就给属性赋值,就需要用到构造方法(Constructor)。
1. 构造方法的特点
- 方法名必须和类名完全一致;
- 没有返回值类型(连void都不能写);
- 在创建对象(new)时自动调用,专门用来做对象的初始化。
2. 无参构造与有参构造
- 无参构造方法:如果你在类里一个构造方法都不写,编译器会默认给你生成一个空的无参构造。
- 有参构造方法:我们自己定义带参数的构造方法,在创建对象时传入参数,给成员变量赋值。
还是用Student类举例:
public class Student {
private String name;
private int age;
// 1. 无参构造方法(默认提供,也可以手动写)
//但最好还是写,因为它有独特的作用
public Student() {
}
// 2. 有参构造方法:创建对象时直接赋值
public Student(String name, int age) {
// this关键字:指代当前正在创建的对象
// 区分成员变量和局部变量
this.name = name;
this.age = age;
}
}
创建对象时就可以直接赋值:
// 调用有参构造,创建对象同时赋值
Student zhangsan = new Student("张三", 18);
这里的 this 关键字,代表“当前对象”,它主要作用就是区分同名的成员变量和局部变量。
而之所以要有this代表“当前对象”,是因为方法是对象才能调用的。相当于得先有人(对象),然后人要有吃饭的行为(方法),最后人才可以执行吃饭的行为(方法),不然没有对象那谁来执行方法呢?所以方法必须在类里面,也必须由类生成对象来执行。搞清关系就好理解面向-对象的含义了。
五、封装:面向对象的核心思想体现
讲到这里,你可能会问:为什么要把 name 和 age 用 private 修饰?为什么不直接设为public让外部随便访问?
这就涉及到面向对象三大特性之首——封装。
1. 封装的思想
封装的核心是:隐藏内部实现细节,对外暴露可控的访问入口。
- 用
private修饰成员变量,让外部不能直接读写属性; - 提供
public修饰的getXxx/setXxx方法,让外部只能通过我们指定的方法访问属性。
这样做的好处是什么?我们可以在方法里加入数据校验,保证数据的合法性。比如年龄不能是负数:
public void setAge(int age) {
if (age >= 0 && age <= 120) {
this.age = age;
} else {
System.out.println("年龄不合法");
}
}
如果属性是public,外部随便赋值一个负数,程序就会出现逻辑错误;而封装之后,所有修改都必须经过我们的校验,数据安全性大大提升。
简单来说有了对象后,我们还要运用对象来勾勒或者说完成对现实问题的解答,而有些对象的特征和行为(变量和方法)是不变的,如果没有private的来约束或者说封装的话那不经意的改变都会使得对象缺胳膊少腿、忘记吃饭睡觉,又或者随意改动账号,这不利于我们使用以及对代码的安全和维护。
六、面向对象的优势
理解了类与对象、封装,我们再回头看面向对象和面向过程的区别:
- 面向过程(C语言为代表):思考的是“步骤”——先做什么,再做什么,函数是最小单位,适合解决简单、线性的问题。
- 面向对象(Java为代表):思考的是“实体”——有哪些角色,每个角色有什么属性、能做什么,类/对象是最小单位。
当软件规模越来越大、需求越来越复杂时,面向对象的优势就会凸显:
- 模块化:每个类负责一个职责,代码结构清晰,便于维护;
- 复用性:一个类可以创建无数个对象,也可以被其他地方复用;
- 扩展性:基于类的继承、多态特性,可以在不修改原有代码的前提下扩展功能。
而这一切的基础,就是类与对象。
更多推荐



所有评论(0)