1 类和对象
1.1 面向对象的介绍
1.1.1 面向过程
是一种以 过程 或 函数 为中心的编程范式,它强调的是 解决问题的步骤。程序被分解为一系列函数或过程的集合,每个函数负责完成一个特定的任务,数据和操作数据的函数是分离的。面向过程编程的核心在于 如何通过一系列步骤来达到目标。
类比: 像做菜,按照菜谱一步步操作,每个步骤是独立的(切菜、炒菜、调味),但需要自己管理材料和工具。
适用场景: 适合解决简单、线性流程的问题,代码结构清晰,但扩展性和复用性较差。
示例: 实现计算器程序,下面是面向过程的代码。
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("Division by zero")
return a / b
# 使用函数
result = add(5, 3)
print(result) # 输出 8
1.1.2 面向对象
面向对象是一种以 对象 为中心的编程范式,它强调的是 数据和操作数据的方法的封装。程序被组织为一系列对象的集合,每个对象包含数据(属性)和操作这些数据的方法(行为)。面向对象编程的核心在于 如何通过对象之间的交互来解决问题。
类比: 像点外卖,你只需要告诉商家(对象)你要什么菜,商家会处理所有细节(切菜、炒菜、调味),你只需要等待结果。
适用场景: 适合解决复杂问题,通过封装、继承和多态等特性提高代码的复用性和扩展性,更符合人类的思维方式。
示例: 实现计算器程序,下面是面向对象的代码。
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
def multiply(self, a, b):
return a * b
def divide(self, a, b):
if b == 0:
raise ValueError("Division by zero")
return a / b
# 使用对象
calc = Calculator()
result = calc.add(5, 3)
print(result) # 输出 8
1.2 类和对象的介绍
1.2.1 类
之前我们学习接触到的类,主要是测试类(带 main 方法的类),其主要是用来运行代码。
接下来学习的是 实体类,它主要是一类事物的抽象表示形式,比如:人类、动物类、手机类等。下面会举例说明。
类的组成部分
类的组成部分主要分为两种:属性(成员变量) 和 行为(成员方法)
- 属性(成员变量),用于描述类对象的状态的数据
- 定义位置:定义在类中的方法外面
- 作用范围:作用于当前类
- 定义格式:
数据类型 变量名 - 定义的时候,可以不用初始化赋值,会有默认值:
- 整数:0
- 小数:0.0
- 字符:
'\u0000' - 布尔:
false - 引用:
null
- 行为(成员方法),用于描述对象可以执行的操作或功能。
示例
以下几个类都属于同个包。
public class Person {
String name;
int age;
public void eat() {
System.out.println("干饭");
}
public void drink() {
System.out.println("喝饮料");
}
}
public class Phone {
String brand;
public void call(){
System.out.println("打电话");
}
}
public class Animal {
String kind;
int num;
public void statistics(){
System.out.println("统计动物数量:" + num);
}
}
public class Demo01 {
public static void main(String[] args) {
Person person = new Person();
person.eat();
Phone phone = new Phone();
phone.call();
Animal animal = new Animal();
animal.num = 100;
animal.statistics();
}
}
注意: 在同个包下的类可以直接使用,而无需导包。
1.2.2 对象
概述:一类事物的具体体现。
使用:
- 导包:
import 包名.类名; - 创建对象,想要使用哪个类中的成员,就 new 哪个类
- 调用成员(成员变量、成员方法),通过 new 出来的对象就可以使用构造出该对象的类里面变量和方法。
package com.testing.oop.Demo02;
public class Phone {
String brand;
String color;
int price;
public void call(String name) {
String callStr1 = "价格为" + price + "的" + color + brand;
String callStr2 = "给" + name + "打电话";
System.out.println(callStr1 + callStr2);
}
public String message(String name) {
return "给" + name + "发短信";
}
}
package com.testing.oop.Demo02;
public class Demo02 {
public static void main(String[] args) {
Phone phone = new Phone();
phone.brand = "HUAWEI";
phone.color = "黑色";
phone.price = 5220;
phone.call("王思聪");
String sms = phone.message("柳岩");
System.out.println(sms);
}
}
/*
价格为5220的黑色HUAWEI给王思聪打电话
给柳岩发短信
*/
1.3 匿名对象的使用
匿名对象是指创建对象(new一个对象)时,不将对象赋值给任何变量,而直接使用对象。
匿名对象的使用时机:当只需要调用一个对象的方法,且不涉及变量的赋值时,可以使用匿名对象。
package com.testing.oop.Demo03;
public class Person {
String name = "";
public void eat() {
if (name.isEmpty()) {
System.out.println("人要吃饭!");
} else {
System.out.println(name + "要吃饭!");
}
}
}
package com.testing.oop.Demo03;
public class Demo03 {
public static void main(String[] args) {
Person person = new Person();
person.name = "姚明";
person.eat();
new Person().eat();
}
}
/*
姚明要吃饭!
人要吃饭!
*/
1.4 对象的内存图
1.4.1 一个对象的内存图
1.4.2 两个对象的内存图
同个 class new 出来两个不同的对象,在内存堆中是各自管理自己的成员变量的,彼此之间互不影响。
1.4.3 两个对象指向同一片堆空间的内存图
两个变量指向同个实例对象,当改变其中一个变量(存储着对象地址)的某个成员变量时,另外一个变量(存储着同个对象地址)也会被同步修改。
1.5 成员变量和局部变量的区别
示例代码:
public class Person {
// 成员变量定义在类内,方法的外面,作用于当前类
String name; // 没有初始化赋值,引用类型默认是 null
int age; // 没有初始化赋值,int 类型默认是 0
public void eat() {
// 局部变量定义方法的代码块内,作用于当前代码块
// String food;
// System.out.println(food); // 未初始化赋值就使用 food,会报错:"变量 'food' 可能尚未初始化"
System.out.println("干饭");
}
public void drink(String thing) {
// 或者局部变量定义在方法的参数上,作用于当前代码块
System.out.println("喝饮料" + thing);
}
}
主要有以下区别:
| 序号 | 区别点 | 成员变量 | 局部变量 |
|---|---|---|---|
| 1 | 定义位置 | 定义在类中方法的外面 | 定义在方法体内,或者方法参数中 |
| 2 | 初始化值 | 初始化后有默认值,不用手动赋值也可直接使用 | 初始化后没有默认值,必须手动赋值才能使用,否则报错 |
| 3 | 作用范围 | 作用于整个 class 中 | 作用于当前方法体内其所在的代码块 |
| 4 | 生命周期 | 随着对象的创建而产生,消失而消失 | 随着方法的调用而产生,调用完毕而消失 |
| 5 | 内存位置 | 在内存堆中,跟着实例对象位置走 | 在内存栈中,跟着方法走 |
1.6 练习
定义一个 MyDate 类,要求成员变量有:year、month、day,再定义一个 Citizen 类,要求成员变量有:name、birthday、idCard,为这三个成员变量赋值,并取值打印。
// /Demo04/MyDate.java
public class MyDate {
String year;
String month;
String day;
}
// /Demo04/Citizen.java
public class Citizen {
String name;
MyDate birthday = new MyDate();
String idCard;
}
// /Demo04/Citizen.java
public class Demo04 {
public static void main(String[] args) {
Citizen citizen = new Citizen();
citizen.name = "江哥";
citizen.birthday.year = "2025";
citizen.birthday.month = "07";
citizen.birthday.day = "07";
citizen.idCard = "auth123";
System.out.println(citizen.name + "_" + citizen.birthday.year + citizen.birthday.month + citizen.birthday.day + "_" + citizen.idCard);
}
}
/*
江哥_20250707_auth123
*/
2 封装
封装的本质是 信息隐藏 和 接口暴露。通过将对象的内部状态(属性)和行为(方法)绑定成一个整体,并对外部隐藏实现细节,仅通过公共接口与外界交互。
这种设计模式有利于:
- 保护数据安全:防止外部直接修改对象的内部状态(如通过
private修饰属性) - 降低耦合度:外部代码只需依赖接口,无需关心内部实现,从而提高代码的可维护性和扩展性
- 模块化设计:将功能封装为独立的单元,便于复用和测试
样例 1
package com.testing.oop.Demo05;
import java.util.Arrays;
public class Demo05Test01 {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
// 这里的 toString 就是一个封装好的功能,通过外界的参数来与其进行交互
System.out.println(Arrays.toString(arr));
}
}
/*
[1, 2, 3, 4]
*/
样例 2
package com.testing.oop.Demo05;
public class Demo05Test02 {
public static void main(String[] args) {
int[] arr = {11, 22, 33, 44};
String res = customToString(arr);
System.out.println(res);
}
// 封装自定义 toString 功能
public static String customToString(int[] arr) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i > 0) {
sb.append(',');
}
sb.append(arr[i]);
}
sb.append("]");
return sb.toString();
}
}
/*
[11,22,33,44]
*/
样例 3
以下 2 个类都属于同个包。
package com.testing.oop.Demo05;
public class Demo05Test03 {
public static void main(String[] args) {
Person p = new Person();
System.out.println("没有 set name & age 之前,Name==" + p.getName() + ",Age==" + p.getAge() );
p.setName("鸣人");
p.setAge(20);
System.out.println("set name & age 之后,Name==" + p.getName() + ",Age==" + p.getAge() );
}
}
/*
没有 set name & age 之前,Name==null,Age==0
set name & age 之后,Name==鸣人,Age==20
*/
package com.testing.oop.Demo05;
public class Person {
private String name;
private int age;
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if (age < 0 || age > 150) {
System.out.println("您是神仙!");
} else {
this.age = age;
}
}
}
2.1 关于 class 中的 this
在类中,this 指向 new 出的当前对象。例如:new 出来的一个对象,调用这个对象中的某个方法,方法中 this 的指向就是这个对象。
package com.testing.oop.Demo05;
public class Demo05Test04 {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println("对象1:" + p1);
p1.findThis("p1"); // this 指向当前对象的地址值
Person p2 = new Person();
System.out.println("对象2:" + p2);
p2.findThis("p2"); // this 指向当前对象的地址值
}
}
package com.testing.oop.Demo05;
public class Person {
public void findThis(String indicator) {
System.out.println(indicator + ": " + this);
}
}