日期:2026-07-20
项目:c260720
作者:WanJL
| 对比维度 | 面向对象(Java) | 面向过程(C) |
|---|---|---|
| 思想核心 | 以对象为中心,通过指挥对象实现操作 | 以过程为中心,功能都由自己实现 |
| 特点 | 更符合人类思维习惯,易于维护和扩展 | 按步骤一步步执行,代码直接 |
| 关键词 | 类、对象、封装、继承、多态 | 函数、过程、步骤 |
Java 中一切皆为对象,是一种以对象为中心的编程思想。
类比:设计图纸(类)与成品(对象)的关系。
类的定义: 类是现实生活中一类具有相同属性和行为的事物的抽象。
修饰符 class 类名 {
数据类型 属性名; // 成员变量(属性)
修饰符 返回值类型 方法名(){ // 成员方法(行为)
}
}
类的成员组成:
| 成员 | 对应概念 | 表现形式 |
|---|---|---|
| 属性(Property) | 事物特征 | 成员变量(类中方法外的变量) |
| 行为(Behavior) | 事物操作 | 成员方法(去掉 static 关键字的方法) |
创建对象格式:
类名 对象名 = new 类名();
调用成员格式:
对象名.成员变量; // 访问属性
对象名.成员方法(); // 调用方法
文件:Demo03.java
| 对比维度 | 成员变量 | 局部变量 |
|---|---|---|
| 类中位置 | 定义在【类内部,方法外部】 | 定义在【方法内部】(方法的参数也属于局部变量) |
| 内存位置 | 堆内存(Heap)中 | 栈内存(Stack)中 |
| 生命周期 | 随着对象的存在而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用结束而消失 |
| 初始化值 | 有默认初始化值(整数→0,引用类型→null) |
没有默认初始化值,必须先定义赋值才能使用 |
public class Student {
String name; // 成员变量 —— 在类内部、方法外部
int age; // 成员变量
public void study() {
String msg = "学习中"; // 局部变量 —— 在方法内部
System.out.println(msg);
}
}
文件:Demo03.java
当多个引用变量指向 同一个内存地址 时,它们操作的是同一块内存空间。任何一个引用修改了数据,其他引用获取到的都是修改后的数据。
public class Demo03 {
public static void main(String[] args) {
Teacher t1 = new Teacher(); // t1 引用指向 0x1024
t1.name = "张三";
t1.sleep(); // 输出:张三在休息....
Teacher t2 = t1; // t2 也指向 0x1024(与 t1 同一对象)
t2.name = "李四";
t2.id = "1001";
t1.sleep(); // 输出:1001李四在休息....(已被 t2 修改)
}
}
图解:
t1和t2是两个不同的引用变量,但存储的是同一个对象的地址0x1024。通过t2.name = "李四"修改后,t1.name也变成"李四",因为它们是同一块内存。
文件:Test01.java, Test02.java
对象数组的数组元素类型是类名,存储的是对象的引用地址(而非对象本身)。
// 定义一个可以存储 10 个 BaiLu 对象引用的数组
BaiLu[] bailus = new BaiLu[10];
// 定义一个可以存储 10 个 Bike 对象引用的数组
Bike[] bikes = new Bike[10];
创建对象并存入数组的标准操作:
// 1. 先创建对象
BaiLu b = new BaiLu();
// 2. 调用对象方法
b.up("青天");
// 3. 将对象引用(地址值)存入数组
bailus[i] = b;
对比基本类型数组:
int[] arr = new int[10]存的是数值;对象数组存的是引用(地址)。
文件:Demo04.java, Person.java, PersonTest.java
Java 面向对象有三大特性,本质上都是为了 减少写代码、让代码能够复用:
| 特性 | 说明 |
|---|---|
| 封装 | 把该隐藏的隐藏起来,把该显示的显示出来 |
| 继承 | 子类自动拥有父类的成员,实现代码复用 |
| 多态 | 同一行为在不同对象上产生不同效果 |
问题场景:如果类的属性直接暴露,可以随意赋值,可能导致不符合业务逻辑的数据。
Person p = new Person();
p.age = 250; // 语法正确,但业务上不合理(人的年龄不可能250岁)
p.age = -250000; // 同样不合理
解决方案(封装两步走):
第一步:把属性的权限提高,让【本类以外】都无法直接访问(赋值、取值)
→ 使用 private 关键字
第二步:定义公开(public)的方法来赋值和取值
→ setXxx() 方法:赋值,内部做合法性判断
→ getXxx() 方法:取值
| 修饰符 | 含义 | 访问范围 |
|---|---|---|
public |
公开的 | 任何地方的任何类都能访问 |
private |
私有的 | 除了自身所在的类之外,任何类都不能访问 |
default(默认) |
默认的 | 本类中、同包中可以访问(不写任何修饰符) |
protected |
受保护的 | 本类中、同包中可以访问,非同包的子类可以访问(讲继承时再细说) |
public class Person {
String name;
private int age; // 私有化:本类以外无法直接访问
// 公开的赋值方法(setter)—— 带合法性校验
public void setAge(int newAge) {
if (newAge >= 1 && newAge < 130) {
age = newAge;
} else {
System.out.println("年龄超过规定限制,赋值无效...");
}
}
// 公开的取值方法(getter)
public int getAge() {
return age;
}
}
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
p.name = "张三";
p.setAge(200); // 赋值无效:年龄超过限制
int age = p.getAge(); // 获取到的 age 是默认值 0
System.out.println(age); // 输出:0
}
}
封装的核心思想:隐藏功能的实现细节,仅暴露功能的调用方式。就像 USB 接口,用户只需插拔,不需关心内部电路。
this 关键字文件:Product.java
当方法参数(局部变量)与成员变量同名时,按照就近原则,方法内部默认使用的是局部变量。此时需要用 this 关键字来区分。
public class Product {
private String brand; // 成员变量
// 参数 brand 与成员变量 brand 同名
public void setBrand(String brand) {
// this.brand 是成员变量,brand 是局部变量(方法参数)
this.brand = brand;
}
}
this的含义:当前对象的引用。this.成员变量调用的一定是当前对象的成员变量,this.成员方法()调用的一定是当前对象的成员方法。
使用 this 的标准 getter/setter 写法:
public void setName(String name) {
this.name = name; // this 区分成员变量和参数
}
public String getName() {
return this.name; // 此处可以省略 this(无同名冲突),但加上更清晰
}
封装的原则:
private 修饰,成员方法使用 public 修饰封装的好处:
文件:Demo02.java / Student.java
定义类(Student.java):
public class Student {
String name; // 成员变量:姓名
int age; // 成员变量:年龄
// 成员方法:学习
public void study() {
System.out.println("姓名:" + name + ",年龄:" + age + ",在学习");
}
}
使用对象(Demo02.java):
public class Demo02 {
public static void main(String[] args) {
// 创建第一个学生对象
Student s = new Student();
s.name = "张三";
s.age = 25;
s.study();
// 创建第二个学生对象
Student s1 = new Student();
s1.name = "李四";
s1.age = 20;
s1.study();
}
}
要点:同一个
Student类可以创建多个对象,每个对象拥有自己独立的属性值。
文件:Dog.java
public class Dog {
double weight; // 成员变量:体重
double height; // 成员变量:身高
public static void main(String[] args) {
Dog d = new Dog();
d.height = 15.6;
d.weight = 3.14;
}
}
文件:Teacher.java / TeacherTest.java
定义类(Teacher.java):
public class Teacher {
String id; // 教工号
String name; // 姓名
int age; // 年龄
public void teaching() {
System.out.println(id + name + age + "在授课....");
}
public void sleep() {
System.out.println(id + name + age + "在休息....");
}
}
测试类(TeacherTest.java)—— 重点:对象地址输出:
public class TeacherTest {
public static void main(String[] args) {
Teacher t = new Teacher();
t.id = "1001";
t.name = "张三";
t.age = 25;
t.teaching();
t.sleep();
// 直接输出对象名 —— 得到内存地址
System.out.println(t);
// 输出示例:Teacher@4769b07b
}
}
直接打印对象名时,输出格式为:类型@哈希码
| 部分 | 含义 |
|---|---|
Teacher |
对象所属的类型 |
@ |
分隔符 |
4769b07b |
对象在内存中的地址(哈希码的十六进制表示) |
文件:HuangLi.java, BaiLu.java, Test01.java
定义类——黄鹂(HuangLi.java):
public class HuangLi {
public void sing(String s) {
System.out.println("黄鹂鸣" + s);
}
}
定义类——白鹭(BaiLu.java):
public class BaiLu {
public void up(String s) {
System.out.println("白鹭上" + s);
}
}
测试类 —— 使用对象数组:
public class Test01 {
public static void main(String[] args) {
// 黄鹂:创建两个对象,调用方法
HuangLi h1 = new HuangLi();
HuangLi h2 = new HuangLi();
String s1 = "翠柳";
h1.sing(s1);
h2.sing(s1);
// 白鹭:对象数组,循环创建 10 个对象
String s2 = "青天";
BaiLu[] bailus = new BaiLu[10];
// 初始状态:数组元素全为 null
System.out.println(Arrays.toString(bailus));
for (int i = 0; i < 10; i++) {
BaiLu b = new BaiLu(); // 创建白鹭对象
b.up(s2); // 调用方法
bailus[i] = b; // 存入数组(存的是地址值)
}
}
}
要点:对象数组刚刚创建时,所有元素默认为
null。需要逐个new对象并赋值后才能使用。
文件:Car.java, Bike.java, Test02.java
定义类——汽车(Car.java):
public class Car {
String brand; // 品牌
String color; // 颜色
public void drive() {
System.out.println(brand + "牌的" + color + "汽车行驶.....");
}
}
定义类——自行车(Bike.java):
public class Bike {
String type; // 车型
public void ride() {
System.out.println("我骑着" + type + "自行车在骑行.....");
}
}
测试类 —— 单个对象 + 对象数组:
public class Test02 {
public static void main(String[] args) {
// 单个汽车对象
Car c = new Car();
c.brand = "奔驰";
c.color = "白色";
c.drive();
// 自行车对象数组
Bike[] bikes = new Bike[10];
for (int i = 0; i < 10; i++) {
Bike b = new Bike();
b.type = "山地";
bikes[i] = b;
bikes[i].ride();
}
}
}
要点:单个对象与对象数组混合使用,展示了面向对象建模中「1 对 N」关系的代码实现。
文件:Person.java, PersonTest.java
完整演示封装的标准实现:私有化属性 + setter/getter 方法。
实体类(Person.java):
public class Person {
String name; // 公开属性
private int age; // 私有属性:外部不能直接访问
// setter:赋值 + 合法性校验
public void setAge(int newAge) {
if (newAge >= 1 && newAge < 130) {
age = newAge;
} else {
System.out.println("年龄超过规定限制,赋值无效...");
}
}
// getter:取值
public int getAge() {
return age;
}
}
测试类(PersonTest.java):
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
p.name = "张三"; // 公开属性可以直接赋值
p.setAge(200); // 通过 setter 赋值(会校验)
int age = p.getAge(); // 通过 getter 取值
System.out.println(age); // 输出 0(因为赋值无效,age 保持默认值)
// p.age = 20; // 编译错误:age 是 private 的,外部无法直接访问
}
}
文件:Product.java
完整的商品封装类,包含 4 个私有属性,每个属性都有标准的 getter/setter,并在参数与成员变量同名时使用 this 关键字。
public class Product {
private String brand; // 品牌
private String name; // 名称
private double price; // 价格
private int count; // 数量
// setter/getter —— 使用 this 区分同名参数和成员变量
public void setBrand(String brand) {
this.brand = brand; // this.brand 是成员变量,brand 是参数
}
public String getBrand() {
return brand; // 无同名冲突,this 可省略
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name; // 加上 this 更清晰
}
public void setPrice(double price) {
this.price = price;
}
public double getPrice() {
return price;
}
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return count;
}
}
要点:当 setter 参数名与成员变量名一致时,
this不能省略,否则方法内使用的都是局部变量,赋值无效。
以下练习在
Demo02.java、Demo03.java和Demo04.java中以注释形式列出,作为课后实现任务。
创建 Teacher 类,包含:
id)、姓名(name)、年龄(age)teaching)——输出 id+name+age老师在授课、休息(sleep)——输出 id+name+age老师在休息创建 Phone 类和 PhoneTest 测试类:
brand)、价格(price)call)、发短信(sendMessage)创建矩形类,包含:
length)、宽度(width)创建圆形类,包含:
radius)创建三角形类,包含:
分析诗句「两只黄鹂鸣翠柳,一行白鹭上青天」,创建对应类和测试类:
HuangLi):sing(String s) 方法BaiLu):up(String s) 方法分析描述「一辆汽车在路上行驶,一队自行车并排骑行」,创建对应类和测试类:
Car):品牌、颜色属性 + drive() 方法Bike):车型属性 + ride() 方法参照 Person 类的封装方式,创建一个 StudentV2 类:
name,公开)、年龄(age,私有)getAge() 方法获取年龄在已有 Person 类基础上,为 name 属性也添加 private 修饰,并配置对应的 setter/getter 方法。
创建 Bird 类,定义 3 个私有成员变量,并对每个成员变量设置赋值和取值的方法(getter/setter),要求参数名与成员变量同名时使用 this 关键字。
为 Product 类创建测试类 ProductTest,创建商品对象并通过 setter 赋值,通过 getter 输出所有属性值。
| 序号 | 知识点 | 说明 | 对应文件 |
|---|---|---|---|
| 1 | 面向对象思想 | Java 以对象为中心,区别于 C 的面向过程 | Demo01.java |
| 2 | 类的定义 | class 关键字定义类,包含属性和行为 |
Demo01.java |
| 3 | 成员变量 | 类中方法外的变量,描述属性 | Student.java, Dog.java, Teacher.java |
| 4 | 成员方法 | 类中定义方法(无 static),描述行为 |
Student.java, Teacher.java |
| 5 | 创建对象 | 类名 对象名 = new 类名(); |
Demo02.java, TeacherTest.java |
| 6 | 调用成员 | 对象名.成员变量 / 对象名.成员方法() |
Demo02.java, TeacherTest.java |
| 7 | 多对象创建 | 一个类可创建多个独立对象 | Demo02.java |
| 8 | 对象地址 | 直接输出对象得到 类型@哈希码 |
TeacherTest.java |
| 9 | 成员变量 vs 局部变量 | 四维对比:位置、内存、生命周期、初始化值 | Demo03.java |
| 10 | 对象引用与内存共享 | 多个引用指向同一内存地址,修改互相影响 | Demo03.java |
| 11 | 对象数组 | 数组元素类型为类名,存储对象引用地址 | Test01.java, Test02.java |
| 12 | 循环创建对象并存入数组 | for 循环中 new 对象,赋值给数组元素 |
Test01.java, Test02.java |
| 13 | 多个类协同建模 | 将现实场景(古诗/交通)抽象为多个类 | HuangLi.java, BaiLu.java, Car.java, Bike.java |
| 14 | 封装(Encapsulation) | 面向对象三大特性之一,隐藏实现细节,暴露调用方式 | Demo04.java |
| 15 | private 关键字 |
私有权限修饰符,本类以外无法访问 | Person.java |
| 16 | setter/getter 方法 | 对外提供公有方法赋值/取值,可做合法性校验 | Person.java, PersonTest.java |
| 17 | this 关键字 |
区分同名的成员变量和局部变量,指向当前对象 | Product.java |
| 18 | default 权限修饰符 |
默认访问权限,同包中可以访问 | Demo04.java |
| 19 | protected 权限修饰符 |
受保护权限,同包+非同包子类可以访问 | Demo04.java |
new 类名() 实际上是调用类的构造方法,默认有无参构造new Student().study(); —— 没有名字的对象,用后即弃null),调用该引用的成员会报空指针异常