本文纲要
- 面向过程与面向对象编程思想对比
- 类与对象的关系
- 类的定义(成员变量与成员方法)
- 对象的创建与使用
- 案例:手机类的创建和使用
- 对象内存图(单个对象、两个对象、两个引用指向同一对象)
- 成员变量与局部变量的区别
- private 关键字与数据安全性
- this 关键字及其内存原理
- 封装思想
- 构造方法的格式与执行时机
- 构造方法的作用
- 构造方法的注意事项
- 标准 JavaBean 类的编写与使用
- 总结
面向过程与面向对象编程思想对比
1 ) 两种思想的定义
面向过程(Procedure Oriented Programming, POP):以过程为中心,每一步都由开发者自己实现。之前编写的所有代码基本都是面向过程的——例如遍历数组、求最大值,都需要手写循环、判断等每一步逻辑。
面向对象(Object Oriented Programming, OOP):以对象为中心,通过“指挥对象”来实现具体功能。重点在“指挥”二字,即找能干活的“对象”帮我们完成需求。
通俗理解:
面向过程 = 自己干活
面向对象 = 找别人(对象)干活
2 ) 生活案例
需求1:吃一盘“普罗旺斯茄块烩马铃薯”(地三鲜)
面向过程:自己买菜、学菜谱、洗菜、做菜……全包。
面向对象:指挥女朋友或厨师做菜,女朋友和厨师就是“对象”。
需求2:洗衣服
面向过程:自己泡衣服、洗、拧、晾。
面向对象:指挥洗衣机或女朋友,洗衣机和女朋友就是“对象”。
3 ) 代码对比
在代码中,同样遍历打印数组的需求,两种思想实现完全不同:
面向过程版本(自己一步步实现):
public class Demo1Pop {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length - 1){
System.out.println(arr[i] + "]");
}else{
System.out.print(arr[i] + ", ");
}
}
}
}
面向对象版本(指挥对象干活):
// 数组服务员对象(为演示思想使用了中文命名,实际开发需用英文)
public class 数组服务员 {
public void 遍历打印数组(int[] arr){
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if(i == arr.length - 1){
System.out.println(arr[i] + "]");
}else{
System.out.print(arr[i] + ", ");
}
}
}
}
public class Demo1Oop {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
数组服务员 二狗 = new 数组服务员();
二狗.遍历打印数组(arr); // 指挥二狗对象干活
}
}
面向对象让我们从“执行者”切换到“指挥者”,但对象内部仍然是按面向过程的步骤实现功能。面向对象是基于面向过程演变而来的。
类与对象的关系
1 ) 什么是类
类是对现实世界一类具有共同属性和行为的事物的抽象,相当于一张“设计图”。例如“学生”类,描述了学生都有姓名、年龄、毕业院校等属性,以及学习、做开发等行为。
类的组成:
属性:事物的各种特征(如姓名、年龄)→ 在代码中用成员变量体现
行为:事物能完成的功能(如学习)→ 在代码中用成员方法体现
2 ) 什么是对象
对象是看得见摸得着的真实存在的实体。类只是描述,对象才是真正存在的具体事物。根据一张设计图(类),可以创建多个具体的对象。
3 ) 类与对象的关系
类是对对象的描述(模板)
对象是类的实体(实例)
例如:Student 类描述了学生这个群体,stu1、stu2 就是具体的学生对象。
类的定义
在 Java 中,类由成员变量和成员方法组成
定义步骤:
- 编写类:public class 类名 { }
- 在类中编写成员变量(属性)
- 在类中编写成员方法(行为)
代码示例:
package com.wb.object1;
public class Student {
// 成员变量:姓名、年龄
String name;
int age;
// 成员方法:学习
public void study(){
System.out.println("学习");
}
}
注意:
成员变量的定义格式与普通变量相同,但位置在类中、方法外。
成员方法的格式与普通方法相同,但去掉 static 关键字。
类只负责描述事物,不应包含具体个人数据(如不应写死 name = “张三”),具体值应在创建对象后赋值。
对象的创建与使用
1 ) 创建对象格式
类名 对象名 = new 类名();
例如:Student stu = new Student();
2 ) 使用成员变量
对象名.变量名
可以对变量赋值或取值。
3 ) 使用成员方法
对象名.方法名();
4 ) 示例代码
package com.wb.object1;
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student(); // 创建对象
System.out.println(stu.name); // null (默认初始化值)
System.out.println(stu.age); // 0
stu.name = "张三"; // 为成员变量赋值
stu.age = 23;
System.out.println(stu.name); // 张三
System.out.println(stu.age); // 23
stu.study(); // 调用成员方法
System.out.println(stu); // 打印地址值
}
}
输出包含内存地址(如 com.wb.object1.Student@b4c966a),其中 @ 前是全类名(包名+类名),@后是十六进制内存地址
案例:手机类的创建和使用
需求:定义手机类,包含品牌、价格属性,以及打电话、发短信方法;在测试类中创建对象并调用。
// Phone.java
package com.wb.test1;
public class Phone {
String brand; // 品牌
int price; // 价格
public void call(String name){
System.out.println("给" + name + "打电话");
}
public void sendMessage(){
System.out.println("群发短信");
}
}
// TestPhone.java
package com.wb.test1;
public class TestPhone {
public static void main(String[] args) {
Phone p = new Phone();
p.brand = "大米";
p.price = 2999;
System.out.println(p.brand + "..." + p.price);
p.call("阿强");
p.sendMessage();
}
}
运行结果:
大米...2999
给阿强打电话
群发短信
对象内存图
1 ) JVM 内存区域简要划分
栈内存:存放方法中的局部变量、方法运行时的内存模型。
堆内存:存放 new 出来的对象、数组,以及成员变量。
方法区:存放 .class 字节码文件(包括成员变量和成员方法的信息)。
2 ) 单个对象内存图
执行流程:
- TestStudent.class 加载进方法区,main 方法进栈。
- 执行 Student stu = new Student(); → 加载 Student.class 进方法区,在堆中开辟空间,成员变量有默认初始化值(name=null, age=0),并存储成员方法的引用地址。
- 将堆中地址赋值给栈中的变量 stu。
- 通过 stu.name 等访问堆中变量,赋值或取值。
- 调用 stu.study() 时,根据堆中方法地址找到方法区中的方法,进栈执行。
3 ) 两个对象内存图
要点:
每个对象在堆中有自己独立的空间,成员变量各自存储。
多个对象共用同一份字节码文件,即共用一个成员方法(方法区中的 study),对象中只记录方法的地址。
4 ) 两个引用指向同一对象
Student stu1 = new Student();
stu1.name = "阿强";
Student stu2 = stu1; // stu2 也指向 stu1 的对象
stu2.name = "阿珍";
System.out.println(stu1.name); // 阿珍
System.out.println(stu2.name); // 阿珍
内存示意图:
当 stu1 = null; 时,stu1 断开引用;若 stu2 也被置为 null,则堆中对象成为垃圾,会被 JVM 的垃圾回收器自动回收。
成员变量与局部变量的区别
| 区别点 | 成员变量 | 局部变量 |
|---|---|---|
| 类中位置 | 类中、方法外 | 方法内部,或方法的形参声明上 |
| 内存位置 | 堆内存(对象内) | 栈内存(方法栈帧内) |
| 生命周期 | 随对象存在而存在,对象消失后消失 | 随方法调用而存在,方法结束弹栈后消失 |
| 默认初始化值 | 有(如 int 为 0,引用类型为 null) | 没有,必须手动赋值后才能使用 |
识别关键:看变量定义的位置,在类中方法外 → 成员变量;在方法中 → 局部变量。
private 关键字
1 ) 为什么需要 private
直接通过 对象名.变量名 访问成员变量存在安全隐患,比如为年龄赋值负数,代码无法阻止。
stu.age = -23; // 不合理,但程序不报错
2 ) private 的作用
private 是一个权限修饰符,可修饰成员变量和成员方法。被 private 修饰的成员只能在本类中访问。
3 ) 标准做法:private + get/set 方法
私有化成员变量后,对外提供公共的 set 和 get 方法进行操作,可在方法中加入校验逻辑。
package com.wb.object2;
public class Student {
String name;
private int age;
// 设置值,加入校验
public void setAge(int a){
if(a >= 0 && a <= 120){
age = a;
}else{
System.out.println("您的年龄不合理");
}
}
// 获取值
public int getAge(){
return age;
}
public void show(){
System.out.println(name + "..." + age);
}
}
测试:
Student stu = new Student();
stu.name = "张三";
stu.setAge(-23); // 输出:您的年龄不合理
stu.show(); // 张三...0
这样,数据的合法性得到了保证,提高了程序的安全性。
this 关键字
1 ) 为什么需要 this
当成员变量和局部变量重名时,Java 遵循就近原则,优先使用局部变量。例如:
public void setName(String name){
name = name; // 左右两边都是局部变量自己给自己赋值,成员变量没有变化
}
为解决重名问题,使用 this 关键字明确指定成员变量。
2 ) this 的作用
this 代表当前对象的引用(地址值)。
可以调用本类的成员变量和成员方法:this.成员变量、this.成员方法()。
3 ) 代码示例与验证
package com.wb.mthis;
public class Student {
private String name;
public void setName(String name){
System.out.println(this); // 打印当前对象的地址
this.name = name;
}
}
public class TestStudent {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1);
s1.setName("张三");
// s1 地址与 setName 中 this 地址一致
Student s2 = new Student();
System.out.println(s2);
s2.setName("李四");
// s2 地址与 setName 中 this 地址一致
}
}
结论:哪个对象调用方法,方法中的 this 就代表哪个对象。
4 ) this 的内存原理
调用方法时,方法入栈,并隐式传递当前对象的地址给 this。因此方法内通过 this. 访问的就是调用该方法的那个对象的成员。
封装
1 ) 封装思想
封装是面向对象三大特征之一(封装、继承、多态),核心思想:隐藏实现细节,仅对外暴露公共的访问方式。
例如:插线板用外壳隐藏内部电路,只露出插孔。
2 ) 代码中的封装体现
private + get/set:将成员变量私有化,只提供公共方法访问,内部校验逻辑对外不可见。
方法抽取:将重复代码提取为方法,调用者只需知道方法名,不关心实现细节。
类封装数据:将零散的变量组成为一个类,通过对象来操作。
3 ) 封装的好处
提高安全性:避免非法数据直接进入。
提高复用性:方法可多处调用。
构造方法的格式和执行时机
1 ) 什么是构造方法
构造方法是在创建对象时自动调用的方法,负责对象的初始化。
2 ) 格式
- 方法名必须与类名完全相同(包括大小写)。
- 没有返回值类型,连 void 都不写。
- 不能使用 return 带回具体返回值。
示例:
public class Student {
private String name;
private int age;
// 构造方法
public Student(){
System.out.println("我是Student类的构造方法");
}
}
3 ) 执行时机
每次使用 new 创建对象时,构造方法自动执行一次,且不能手动调用。创建几次对象就执行几次。
构造方法的作用
构造方法的核心作用是创建对象。利用执行时机,可以在构造方法中为对象的成员变量赋初始值(即对象初始化)
带参构造方法
public class Student {
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age;
System.out.println("我是Student类的构造方法");
}
public void show(){
System.out.println(name + "..." + age);
}
}
使用时直接在 new 的同时传入参数:
Student stu = new Student("张三", 23);
stu.show(); // 张三...23
这样可以在创建对象的同时完成属性赋值,非常便捷。
构造方法的注意事项
- 默认构造方法:如果一个类没有定义任何构造方法,系统会自动提供一个无参构造方法。
- 自定义覆盖:一旦手动定义了构造方法(无论带参还是无参),系统就不再提供默认构造方法。
- 建议:开发中,无论是否需要,都手动写出无参构造和带参构造,避免因缺少构造方法而报错。
- 重载:多个构造方法参数列表不同,构成重载关系。
public Student() {} // 无参构造
public Student(String name, int age) { ... } // 带参构造
标准 JavaBean 类的编写与使用
1 ) 标准类(JavaBean)规范
所有成员变量使用 private 修饰
提供无参构造方法和带参构造方法
为每个成员变量提供 setXxx 和 getXxx 方法
提供显示对象信息的方法(如 show)
package com.wb.test3;
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 name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show(){
System.out.println(name + "..." + age);
}
}
2 ) 测试使用
public class TestStudent {
public static void main(String[] args) {
// 方式一:无参构造 + set方法赋值
Student stu1 = new Student();
stu1.setName("张三");
stu1.setAge(23);
stu1.show();
// 方式二:带参构造直接赋值
Student stu2 = new Student("李四", 24);
stu2.show();
}
}
输出:
张三...23
李四...24
3 ) IDEA 快捷生成
在类中右击 → Generate → Constructor 可自动生成无参/带参构造,选择 Getter and Setter 可自动生成 get/set 方法。开发中可极大提升效率。
总结
本篇文章从零开始,讲解了 Java 面向对象编程的核心基础:类与对象、封装、构造方法、this 关键字以及内存原理。掌握这些内容,是进一步学习继承、多态等高级特性的前提。

809

被折叠的 条评论
为什么被折叠?



