第5篇:Java面向对象基础:类与对象、封装与构造方法全解析
2026/4/25 21:36:45 网站建设 项目流程

上一篇我们掌握了Java数组与字符串,能通过数组存储多个数据、通过字符串处理文本信息,完成了简单的综合实战(学生信息管理)。但这些代码依然是“面向过程”的——我们关注的是“步骤”,比如“先录入学生信息、再打印、再求平均分”,一步步执行。而Java是一门面向对象的编程语言,面向对象编程(OOP)是Java的核心思想,能让代码更具复用性、扩展性和可维护性,也是实际开发中最常用的编程思想。

面向对象编程的核心是“类与对象”,我们通过“类”来抽象事物的共性,通过“对象”来具体实现事物的特性,再通过“封装”隐藏事物的细节、暴露必要的功能,让代码更安全、更简洁。本篇文章将从基础入手,手把手教你理解类与对象的概念、区别与联系,掌握成员变量、成员方法、构造方法的用法,吃透封装特性,拆解新手高频易错点(比如类与对象混淆、构造方法误用),结合实战案例,带你从“面向过程”正式转向“面向对象”编程。

核心目标:理解面向对象编程思想,掌握类与对象的定义、创建与使用,熟练运用成员变量、成员方法、构造方法,理解封装特性并能实现封装,能独立完成简单的面向对象实战案例(比如学生类、手机类),规避常见坑,为后续学习继承、多态筑牢基础。

一、前置认知:面向过程 vs 面向对象(核心区别)

在学习面向对象之前,我们先明确“面向过程”和“面向对象”的核心区别,理解为什么需要面向对象编程——它能解决面向过程编程的痛点(代码复用性差、扩展性差、维护困难)。

1.1 面向过程编程(POP)

核心思想:关注步骤,一步一步实现功能。把一个复杂的问题拆解成多个简单的步骤,每个步骤用一段代码实现,最终将所有步骤串联起来,完成功能。

举例:实现“学生成绩管理”(面向过程)

  1. 步骤1:定义数组,存储学生姓名和成绩;

  2. 步骤2:录入学生姓名和成绩(写一段录入代码);

  3. 步骤3:打印学生信息(写一段打印代码);

  4. 步骤4:求平均成绩(写一段计算代码);

  5. 步骤5:查找学生信息(写一段查找代码)。

特点:代码是“线性的”,步骤清晰,但复用性差(比如另一个项目需要录入学生信息,无法直接复用之前的代码)、扩展性差(比如要增加“修改成绩”功能,需要修改大量原有代码)、维护困难(代码杂乱,一个步骤出错,整个流程都受影响)。

1.2 面向对象编程(OOP)

核心思想:关注“对象”,通过对象实现功能。把一个复杂的问题拆解成多个“对象”,每个对象负责一个具体的功能,对象之间通过交互完成整个需求。对象是由“类”创建的,类是对象的“模板”,封装了对象的属性(特征)和方法(行为)。

举例:实现“学生成绩管理”(面向对象)

  1. 定义“学生类(Student)”:封装学生的属性(姓名、成绩)和方法(录入信息、展示信息);

  2. 定义“成绩管理类(StudentManager)”:封装管理功能(打印所有学生、求平均分、查找学生);

  3. 创建学生对象、成绩管理对象;

  4. 通过对象调用方法,完成所有功能。

特点:代码是“模块化的”,每个对象负责自己的功能,复用性强(学生类可以在多个项目中复用)、扩展性强(增加“修改成绩”功能,只需给学生类增加一个方法)、维护简单(每个模块独立,出错后只需修改对应对象的代码)。

1.3 核心区别总结(新手必记)

编程思想

核心关注点

特点

举例

面向过程(POP)

步骤、流程

简单直接,复用性差、扩展性差

用数组+循环实现学生成绩管理

面向对象(OOP)

对象、模块

复用性强、扩展性强、易维护

用Student类+Manager类实现学生成绩管理

核心结论:面向对象是对面向过程的优化,更适合复杂项目的开发,也是Java的核心思想,后续我们所有的开发都会围绕“类与对象”展开。

二、核心概念:类与对象(重中之重)

类与对象是面向对象编程的基础,二者是“模板与实例”的关系,必须彻底理解二者的区别与联系,否则后续学习会非常困难。

2.1 类(Class):对象的模板

类是抽象的,是对一类事物的“共性描述”,包含事物的“属性”(特征)和“方法”(行为)。比如“学生”是一个类,它的属性有姓名、年龄、成绩,方法有学习、考试、展示信息;“手机”是一个类,它的属性有品牌、型号、价格,方法有打电话、发消息、拍照。

类的核心作用:定义事物的属性和方法,作为创建对象的“模板”——一个类可以创建多个对象,每个对象都拥有类中定义的所有属性和方法,但属性的值可以不同。

2.2 对象(Object):类的实例

对象是具体的,是根据类创建出来的“具体实例”,拥有类中定义的所有属性和方法,且每个对象的属性都有具体的值。比如根据“学生类”创建出“张三”“李四”两个对象:张三的姓名是“张三”、成绩是90,李四的姓名是“李四”、成绩是85,二者都有“学习”“展示信息”的方法,但属性值不同。

对象的核心作用:具体实现类中定义的功能,是代码执行的最小单元。

2.3 类与对象的关系(类比理解,新手必懂)

用生活中的例子类比,快速理解类与对象的关系:

  • 类 = 汽车设计图(模板):定义了汽车的属性(品牌、颜色、排量)和方法(行驶、刹车),是抽象的,不能直接使用;

  • 对象 = 具体的汽车(实例):根据设计图制造出来的具体汽车,有具体的品牌(丰田)、颜色(白色)、排量(1.5T),能执行行驶、刹车的方法,是具体的,可以直接使用;

  • 关系:一个设计图(类)可以制造出多辆汽车(对象),所有汽车都拥有设计图中定义的属性和方法,但具体属性值不同。

2.4 类的定义格式(固定写法,必须掌握)

Java中,类的定义有固定格式,包含类名、属性(成员变量)、方法(成员方法)三部分,语法格式如下:

// 类的定义格式 public class 类名 { // 1. 成员变量(属性):定义类的特征,直接写在类中,方法外 数据类型 变量名1; 数据类型 变量名2; ... // 2. 成员方法(行为):定义类的功能,写在类中 public 返回值类型 方法名(参数列表) { 方法体; // 具体功能实现 return 返回值; // 若返回值类型是void,可省略return } }

关键说明:

  • 类名:遵循“大驼峰命名法”(首字母大写,后续每个单词首字母也大写),比如Student、Phone、StudentManager,不能用关键字(比如class、int);

  • 成员变量:直接定义在类中、方法外,无需初始化,系统会赋默认值(和数组、基本数据类型默认值一致);

  • 成员方法:和之前学的方法类似,但无需加static关键字(加static的是静态方法,后续讲解),直接写在类中。

2.5 对象的创建与使用(核心操作)

对象是根据类创建的,创建对象的过程称为“实例化”,使用对象的核心是“调用成员变量”和“调用成员方法”。

(1)对象的创建格式(实例化对象)
// 格式:类名 对象名 = new 类名(); 类名 对象名 = new 类名(); // 示例(根据Student类创建对象) Student zhangsan = new Student();

说明:new关键字的作用是“在内存中为对象分配空间”,创建对象后,对象名(zhangsan)就指向内存中的对象,通过对象名就能操作对象的属性和方法。

(2)对象的使用:调用成员变量和成员方法
// 1. 调用成员变量:对象名.成员变量名 对象名.成员变量名 = 值; // 给成员变量赋值 对象名.成员变量名; // 获取成员变量的值 // 2. 调用成员方法:对象名.方法名(参数); 对象名.方法名(参数);
实战案例:定义学生类(Student),创建对象并使用
// 1. 定义学生类(Student) public class Student { // 成员变量(属性):姓名、年龄、成绩 String name; int age; double score; // 成员方法(行为):展示学生信息 public void showInfo() { System.out.println("姓名:" + name + ",年龄:" + age + ",成绩:" + score); } // 成员方法:学习(无返回值,无参数) public void study() { System.out.println(name + "正在学习Java!"); } // 成员方法:考试(有参数,有返回值) public double exam(String subject) { System.out.println(name + "参加" + subject + "考试"); return score; // 返回成绩 } } // 2. 测试类(包含main方法,创建对象并使用) public class StudentTest { public static void main(String[] args) { // 第一步:创建学生对象(实例化对象) Student zhangsan = new Student(); // 第二步:给对象的成员变量赋值 zhangsan.name = "张三"; zhangsan.age = 18; zhangsan.score = 90.5; // 第三步:调用对象的成员方法 zhangsan.showInfo(); // 调用showInfo方法,展示信息 zhangsan.study(); // 调用study方法 double examScore = zhangsan.exam("Java"); // 调用exam方法,接收返回值 System.out.println("考试成绩:" + examScore); // 再创建一个学生对象(同一个类可以创建多个对象) Student lisi = new Student(); lisi.name = "李四"; lisi.age = 19; lisi.score = 85.0; lisi.showInfo(); lisi.study(); } }

运行结果:

姓名:张三,年龄:18,成绩:90.5 张三正在学习Java! 张三参加Java考试 考试成绩:90.5 姓名:李四,年龄:19,成绩:85.0 李四正在学习Java!

避坑点1:必须先创建对象(new 类名()),才能调用成员变量和成员方法;直接用“类名.成员变量”“类名.方法名”会报错(除非是静态属性/方法)。

避坑点2:不同对象的成员变量是独立的,修改一个对象的成员变量,不会影响另一个对象(比如修改zhangsan的name,lisi的name不会变)。

三、类的核心组成:成员变量 vs 局部变量(新手易混淆)

在类中,我们会遇到两种变量:成员变量(定义在类中、方法外)和局部变量(定义在方法中、代码块中),二者的作用域、默认值、生命周期都不同,是新手最易混淆的知识点之一,必须严格区分。

3.1 成员变量与局部变量的核心区别

区别维度

成员变量

局部变量

定义位置

类中、方法外

方法中、代码块中(比如for循环中)

默认值

有默认值(和基本数据类型、引用类型默认值一致)

无默认值,必须先初始化(赋值)才能使用

作用域

整个类(所有成员方法都能访问)

仅当前方法/代码块(出了方法/代码块就无法访问)

生命周期

和对象一致(对象创建,成员变量存在;对象销毁,成员变量消失)

和方法/代码块一致(方法执行,局部变量存在;方法结束,局部变量消失)

命名冲突

不能和类中其他成员变量重名

可以和成员变量重名,局部变量优先级更高(方法中优先使用局部变量)

实战演示(区分成员变量与局部变量)

public class VariableDemo { // 成员变量(类中、方法外) int num1 = 10; // 有默认值,可直接使用(也可手动赋值) String str1; // 有默认值null public void test() { // 局部变量(方法中) int num2; // 无默认值,必须先赋值才能使用 // System.out.println(num2); // 错误:未初始化 num2 = 20; // 初始化局部变量 String str2 = "局部变量"; // 定义时直接初始化 // 局部变量和成员变量重名,局部变量优先级更高 int num1 = 30; System.out.println("局部变量num1:" + num1); // 输出30(使用局部变量) System.out.println("成员变量num1:" + this.num1); // 输出10(用this关键字访问成员变量) // 访问局部变量 System.out.println("局部变量num2:" + num2); // 输出20 System.out.println("局部变量str2:" + str2); // 输出局部变量 } public static void main(String[] args) { VariableDemo demo = new VariableDemo(); demo.test(); // 访问成员变量(通过对象) System.out.println("成员变量num1:" + demo.num1); // 输出10 System.out.println("成员变量str1:" + demo.str1); // 输出null // 无法访问局部变量(局部变量作用域仅在test方法中) // System.out.println(num2); // 错误:找不到变量num2 } }

避坑点3:局部变量无默认值,必须先初始化才能使用;成员变量有默认值,可直接使用(但建议手动赋值,避免使用默认值导致逻辑错误)。

避坑点4:当局部变量和成员变量重名时,用this关键字访问成员变量(this代表当前对象,后续详细讲解),否则会优先使用局部变量。

四、面向对象核心特性:封装(重点,必懂)

封装是面向对象的三大特性之一(另外两个是继承、多态,后续讲解),核心思想是“隐藏细节,暴露接口”——将类的成员变量(属性)隐藏起来,不允许外部直接访问,而是通过提供“getter方法”(获取属性值)和“setter方法”(设置属性值)来访问和修改属性,这样可以控制属性的访问权限,避免属性被非法修改,让代码更安全、更易维护。

4.1 为什么需要封装?(解决什么问题)

没有封装的问题:外部可以直接访问和修改类的成员变量,容易导致非法数据录入,破坏数据的安全性。

举例(无封装的问题):

public class Student { // 无封装:成员变量直接暴露,外部可直接修改 String name; int age; double score; public void showInfo() { System.out.println("姓名:" + name + ",年龄:" + age + ",成绩:" + score); } } public class Test { public static void main(String[] args) { Student student = new Student(); // 外部直接修改成员变量,可录入非法数据(年龄为负数、成绩超过100) student.age = -18; // 非法年龄 student.score = 150; // 非法成绩 student.showInfo(); // 输出:姓名:null,年龄:-18,成绩:150(数据错误) } }

问题:外部可以随意修改成员变量,没有任何限制,导致数据错误,这就是没有封装的弊端。而封装可以解决这个问题,通过控制属性的访问权限,过滤非法数据。

4.2 封装的实现步骤(固定写法)

封装的实现分为3步,核心是“用private修饰成员变量,提供getter/setter方法”:

  1. private关键字修饰成员变量:将成员变量隐藏起来,外部无法直接访问(private表示“私有”,仅当前类可访问);

  2. 提供getter方法:用于获取成员变量的值,方法名格式:get+成员变量名(首字母大写),返回值类型和成员变量一致,无参数;

  3. 提供setter方法:用于设置成员变量的值,方法名格式:set+成员变量名(首字母大写),无返回值(void),有一个参数(和成员变量类型一致),可在方法中添加逻辑,过滤非法数据。

4.3 封装实战案例(规范写法)

对Student类进行封装,控制年龄和成绩的合法性(年龄≥0,成绩0~100):

public class Student { // 第一步:用private修饰成员变量(隐藏细节) private String name; private int age; private double score; // 第二步:提供getter方法(获取属性值) public String getName() { return name; } // 第三步:提供setter方法(设置属性值,添加逻辑过滤) public void setName(String name) { this.name = name; // this.name指成员变量,name指参数 } public int getAge() { return age; } // 设置年龄:过滤非法数据(年龄≥0) public void setAge(int age) { if (age >= 0) { this.age = age; // 合法数据,赋值 } else { System.out.println("年龄非法!请输入≥0的数字"); // 非法数据,提示 } } public double getScore() { return score; } // 设置成绩:过滤非法数据(0≤成绩≤100) public void setScore(double score) { if (score >= 0 && score <= 100) { this.score = score; } else { System.out.println("成绩非法!请输入0~100之间的数字"); } } // 成员方法:展示学生信息 public void showInfo() { System.out.println("姓名:" + getName() + ",年龄:" + getAge() + ",成绩:" + getScore()); } } // 测试类 public class StudentTest { public static void main(String[] args) { Student student = new Student(); // 无法直接访问private修饰的成员变量(报错) // student.name = "张三"; // 错误:name是private,外部无法访问 // 通过setter方法设置属性值(会过滤非法数据) student.setName("张三"); student.setAge(-18); // 输出:年龄非法!请输入≥0的数字(不赋值) student.setAge(18); // 合法,赋值 student.setScore(150); // 输出:成绩非法!请输入0~100之间的数字(不赋值) student.setScore(90.5); // 合法,赋值 // 通过getter方法获取属性值 System.out.println("学生姓名:" + student.getName()); // 输出张三 System.out.println("学生年龄:" + student.getAge()); // 输出18 // 调用方法展示信息 student.showInfo(); // 输出:姓名:张三,年龄:18,成绩:90.5 } }

运行结果:

年龄非法!请输入≥0的数字 成绩非法!请输入0~100之间的数字 学生姓名:张三 学生年龄:18 姓名:张三,年龄:18,成绩:90.5

核心优势:通过封装,外部无法直接修改成员变量,只能通过setter方法设置,且setter方法中可以添加逻辑,过滤非法数据,保证了数据的安全性;同时,隐藏了类的内部细节,外部只需调用getter/setter方法,无需关心内部实现,降低了代码的耦合度。

4.4 封装的常见易错点

  1. 忘记用private修饰成员变量:依然让成员变量暴露,无法实现封装的效果;

  2. getter/setter方法命名错误:比如getAge写成getage、setAge写成setage(首字母未大写),导致无法正常调用;

  3. setter方法中未添加逻辑过滤:虽然用了private修饰,但setter方法直接赋值,没有过滤非法数据,失去了封装的核心意义;

  4. 混淆this关键字:在setter/getter方法中,未用this区分成员变量和参数,导致赋值失败(比如setName(String name) { name = name; },无法给成员变量赋值)。

五、对象的初始化:构造方法(重点,必懂)

我们之前创建对象后,需要通过setter方法给成员变量赋值,步骤比较繁琐。而构造方法的核心作用是“创建对象时,直接给成员变量赋值”,简化对象的初始化过程,无需再手动调用setter方法。

构造方法是类的特殊方法,创建对象时(new 类名())会自动调用,无需手动调用。

5.1 构造方法的定义格式(固定写法)

// 构造方法格式 public 类名(参数列表) { 方法体; // 给成员变量赋值 }

关键说明(核心特点,必须记住):

  • 构造方法的方法名必须和类名完全一致(大小写也要一致),不能有返回值类型(即使是void也不能写);

  • 构造方法没有返回值,也不能写return语句(除非是return;,表示结束方法);

  • 创建对象时,会自动调用构造方法(new 类名() 就是调用构造方法);

  • 如果类中没有手动定义构造方法,Java会自动提供一个“无参构造方法”(默认构造方法),无参数、无方法体;

  • 如果类中手动定义了构造方法,Java就不会再提供默认的无参构造方法(建议手动添加无参构造方法,避免报错)。

5.2 构造方法的分类(2种,常用)

(1)无参构造方法(无参数)

作用:创建对象时,给成员变量赋默认值(和系统默认值一致),或手动给成员变量赋初始值。

// 无参构造方法(方法名和类名一致,无参数,无返回值) public Student() { // 可手动给成员变量赋初始值 this.name = "未知姓名"; this.age = 0; this.score = 0.0; }
(2)有参构造方法(有参数)

作用:创建对象时,直接给成员变量赋具体的值,无需再调用setter方法,简化初始化步骤。

// 有参构造方法(参数对应成员变量) public Student(String name, int age, double score) { // 用this关键字区分成员变量和参数,给成员变量赋值 this.name = name; this.age = age; this.score = score; }

5.3 构造方法实战案例(规范写法)

给Student类添加无参构造方法和有参构造方法,简化对象初始化:

public class Student { // 私有成员变量(封装) private String name; private int age; private double score; // 1. 无参构造方法(手动添加,避免默认构造方法被覆盖) public Student() { System.out.println("无参构造方法被调用,创建对象!"); // 给成员变量赋初始值 this.name = "未知姓名"; this.age = 0; this.score = 0.0; } // 2. 有参构造方法(3个参数,直接赋值) public Student(String name, int age, double score) { System.out.println("有参构造方法被调用,创建对象!"); // 过滤非法数据(和setter方法逻辑一致) this.name = name; if (age >= 0) { this.age = age; } else { this.age = 0; System.out.println("年龄非法,默认赋值为0"); } if (score >= 0 && score <= 100) { this.score = score; } else { this.score = 0.0; System.out.println("成绩非法,默认赋值为0.0"); } } // getter/setter方法(封装必备) public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { if (age >= 0) { this.age = age; } else { System.out.println("年龄非法!"); } } public double getScore() { return score; } public void setScore(double score) { if (score >= 0 && score <= 100) { this.score = score; } else { System.out.println("成绩非法!"); } } // 展示信息方法 public void showInfo() { System.out.println("姓名:" + name + ",年龄:" + age + ",成绩:" + score); } } // 测试类 public class StudentTest { public static void main(String[] args) { // 1. 调用无参构造方法创建对象 Student student1 = new Student(); student1.showInfo(); // 输出:姓名:未知姓名,年龄:0,成绩:0.0 // 2. 调用有参构造方法创建对象(合法数据) Student student2 = new Student("张三", 18, 90.5); student2.showInfo(); // 输出:姓名:张三,年龄:18,成绩:90.5 // 3. 调用有参构造方法创建对象(非法数据) Student student3 = new Student("李四", -19, 150); student3.showInfo(); // 输出:年龄非法,默认赋值为0;成绩非法,默认赋值为0.0;姓名:李四,年龄:0,成绩:0.0 } }

运行结果:

无参构造方法被调用,创建对象! 姓名:未知姓名,年龄:0,成绩:0.0 有参构造方法被调用,创建对象! 姓名:张三,年龄:18,成绩:90.5 有参构造方法被调用,创建对象! 年龄非法,默认赋值为0 成绩非法,默认赋值为0.0 姓名:李四,年龄:0,成绩:0.0

六、新手高频易错点总结(必看,避坑指南)

  1. 类与对象混淆:误以为类可以直接使用,忘记创建对象(new 类名())就调用成员变量/方法;

  2. 成员变量与局部变量混淆:局部变量未初始化就使用,或混淆二者的作用域;

  3. 封装实现不规范:未用private修饰成员变量,或未提供getter/setter方法,或setter方法未过滤非法数据;

  4. 构造方法误用:构造方法名与类名不一致、添加返回值类型、未添加无参构造方法;

  5. this关键字误用:未用this区分成员变量和参数,导致赋值失败;

  6. 静态方法与成员方法混淆:在成员方法中调用静态方法(可以),但在静态方法中调用成员方法/变量(错误,静态方法不依赖对象,无法访问成员变量/方法)。

七、总结与下期预告

本篇文章重点讲解了Java面向对象的基础核心——类与对象、封装、构造方法,这是面向对象编程的基石,也是后续学习继承、多态、接口的前提。我们理解了面向对象与面向过程的区别,掌握了类的定义、对象的创建与使用,学会了用封装保护数据安全,用构造方法简化对象初始化,同时通过综合实战案例,感受了面向对象编程的优势(复用性强、扩展性强)。

动手练习建议:1. 定义一个Phone类(封装品牌、型号、价格,提供构造方法、getter/setter方法、打电话/发消息方法);2. 完善学生成绩管理案例,增加“修改学生成绩”“删除学生信息”功能;3. 定义一个Person类,封装姓名、年龄,实现封装和构造方法,测试类中创建多个对象并使用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询