一、【核心概念/问题引入】
1.1 先搞懂核心:面向对象到底是什么?
把面向对象比作洗衣机洗衣服,一秒就懂了:
面向过程会将任务拆解成一系列的步骤(函数),1、打开洗衣机>2、放衣服…>3、放洗衣粉…>4、启动>5、烘干
面向对象会拆出人和洗衣机两个对象:
人:打开洗衣机、放衣服、放洗衣粉
洗衣机:清洗烘干
官方定义是:面向对象编程是一种编程思想,它将现实世界中的事物抽象为「对象」,通过对象之间的交互来完成任务,而不是像面向过程那样按照步骤执行。
1.2 为什么需要面向对象?
- 没有面向对象:代码难以维护,修改一个功能需要改很多地方,容易出错
- 有了面向对象:代码更模块化,可复用性更高,修改和扩展都更方便
二、【核心知识点详解】
2.1 类和对象:面向对象的核心基石
是什么:
- 类(Class):是一个抽象的模板/蓝图/设计图,用来定义「某一类东西」的共同特征和行为
- 对象(Object):是类造出来的具体、实实在在的个体,也叫「类的实例」
怎么用: - 定义类:
class 类名 { 属性; 方法; } - 创建对象:
类名 对象名 = new 类名(); - 使用对象:
对象名.属性或对象名.方法()
注意事项: - 类是抽象的,不占内存;对象是具体的,在内存里真实存在
- 一个类可以创建无数个对象
- 没有类就没有对象
代码示例:
// 定义类
class Cat {
// 属性:姓名、年龄、颜色
String name;
String color;
int age;
// 方法:猫的行为
public void eat() {
System.out.println(name + " 喜欢吃鱼🐟");
}
public void run() {
System.out.println(name + "跑了🏃♂️");
}
}
// 创建对象
Cat daHuang = new Cat();
// 使用对象
daHuang.name = "大黄";
daHuang.color = "黄色";
daHuang.age = 2;
daHuang.eat(); // 输出:大黄 喜欢吃鱼🐟
daHuang.run(); // 输出:大黄跑了🏃♂️
2.2 Java 对象在内存中的执行流程
是什么:Java 对象从创建到使用的完整内存变化过程。
内存区域:
- 栈内存:存储对象的引用变量、基本数据类型
- 堆内存:存储真正的对象本身
- 方法区:存储类的模板(属性、方法)
执行流程:
- 加载类模板:JVM 读取类的模板,存到方法区
- 栈内存声明引用:创建引用变量,指向 null
- 堆内存创建对象:分配空间,赋默认值,分配地址
- 给对象属性赋值:通过地址找到对象,修改值
- 调用对象方法:通过引用找到对象,执行方法
注意事项:
- 栈里只有地址,没有真实数据
- 堆里才是真实的对象,存着属性值
- 所有方法都存在方法区,所有对象共用一套方法
2.3 成员变量和局部变量的区别
代码示例:
class Test {
// 成员变量
int memberVar;
public void testMethod() {
// 局部变量
int localVar = 10;
System.out.println(memberVar); // 输出 0(默认值)
System.out.println(localVar); // 输出 10
}
}
2.4 this 关键字
是什么:this 代表「当前正在调用方法的那个对象」的引用。
核心作用:
- 解决成员变量和局部变量重名:
this.变量名强制访问成员变量 - 调用本类的成员方法:
this.方法名(),通常可省略this - 调用本类的构造方法:
this(参数),必须在构造方法的第一行 - 把当前对象作为参数传递:
showCat(this)
注意事项:
static方法里绝对不能用thisthis()调用构造方法必须在第一行- 重名时
this不能省略,非重名时可省略 this代表对象,不是类
代码示例:
class Cat {
String name;
int age;
// 无参构造:用this调用有参构造
public Cat() {
this("无名小猫", 0);
}
// 有参构造:用this解决重名
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
// setName方法:用this解决重名
public void setName(String name) {
this.name = name;
}
}
2.5 构造方法
是什么:构造方法是 Java 类里一种特殊的方法,专门用来创建对象。
格式:
public 类名(参数列表) {
// 方法体:给对象的成员变量赋值、做初始化操作
}
核心要求:
- 方法名必须和类名完全一致(包括大小写)
- 没有返回值类型(连
void都不能写) - 可以带参数,也可以不带参数
作用:
- 创建对象:执行
new 类名()时自动调用 - 初始化对象属性:创建对象时给成员变量赋初始值
注意事项: - 如果没有手动写构造方法,Java 会自动生成一个空的无参构造
- 一旦手动写了构造方法,Java 就不再自动生成默认无参构造
- 构造方法支持重载
- 构造方法不能被对象手动调用
- 构造方法不能被继承
代码示例:
class Cat {
// 1. 无参构造方法(没有参数)
public Cat() {
System.out.println("无参构造被调用了!");
}
// 2. 有参构造方法(带参数)
public Cat(String name, int age) {
this.name = name;
this.age = age;
System.out.println("有参构造被调用了!");
}
// 成员变量
String name;
int age;
}
2.6 灵魂拷问:为什么要使用面向对象?
"学到这你可能有疑问:面向对象看起来比面向过程复杂,为什么还要使用它?"
原因是:
- 可维护性:代码模块化,修改一个功能不会影响其他部分
- 可复用性:类可以被多次实例化,代码可以重复使用
- 可扩展性:可以通过继承、多态等特性轻松扩展功能
- 更符合现实世界:现实世界中的事物本来就是对象,面向对象更贴近我们的思维方式
三、【实战案例】
3.1 案例 1:手机类的设计与使用
需求描述:设计一个手机类,包含品牌、颜色、价格等属性,以及打电话、发短信等方法。
代码实现:
public class Phone {
String brand;
String color;
double price;
public void call() {
System.out.println("用" + brand + "颜色为" + color + ",价格为" + price + ",可以给打电话");
}
public void sendMessage() {
System.out.println("用" + brand + "颜色为" + color + ",价格为" + price + ",可以群发短信");
}
}
public class PhoneTest {
public static void main(String[] args) {
// 创建两个手机对象
Phone huawei = new Phone();
huawei.brand = "华为";
huawei.color = "极夜紫";
huawei.price = 5999.0;
huawei.call();
huawei.sendMessage();
System.out.println("==================");
Phone xiaomi = new Phone();
xiaomi.brand = "小米";
xiaomi.color = "冷翠银";
xiaomi.price = 4999;
xiaomi.call();
xiaomi.sendMessage();
}
}
运行结果:
用华为颜色为极夜紫,价格为5999.0,可以给打电话
用华为颜色为极夜紫,价格为5999.0,可以群发短信
==================
用小米颜色为冷翠银,价格为4999.0,可以给打电话
用小米颜色为冷翠银,价格为4999.0,可以群发短信
3.2 案例 2:使用 this 关键字和构造方法
需求描述:设计一个猫类,使用构造方法初始化属性,使用 this 关键字解决重名问题。
代码实现:
class Cat {
String name;
int age;
// 无参构造:用this调用有参构造
public Cat() {
this("无名小猫", 0);
}
// 有参构造:用this解决重名
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
// setName方法:用this解决重名
public void setName(String name) {
this.name = name;
}
// 调用本类成员方法
public void eat() {
System.out.println(this.name + "喜欢吃鱼🐟");
this.run();
}
public void run() {
System.out.println(this.name + "跑起来了!");
}
}
public class CatTest {
public static void main(String[] args) {
// 1. 测试无参构造+this调用有参
Cat cat1 = new Cat();
cat1.eat();
System.out.println("==========");
// 2. 测试有参构造+this解决重名
Cat daHuang = new Cat("大黄", 2);
daHuang.eat();
System.out.println("==========");
// 3. 测试setName+this解决重名
daHuang.setName("大橘");
daHuang.eat();
}
}
运行结果:
无名小猫喜欢吃鱼🐟
无名小猫跑起来了!
==========
大黄喜欢吃鱼🐟
大黄跑起来了!
==========
大橘喜欢吃鱼🐟
大橘跑起来了!
四、【避坑指南/常见问题】
⚠️ 坑点 1:构造方法没有写对格式
错误写法:
class Cat {
// 错误:构造方法不能有返回值类型
public void Cat() {
System.out.println("构造方法");
}
}
正确写法:
class Cat {
// 正确:构造方法没有返回值类型
public Cat() {
System.out.println("构造方法");
}
}
原因分析:构造方法的格式要求严格,不能有返回值类型,连 void 都不能写。
⚠️ 坑点 2:忘记手动添加无参构造
错误写法:
class Cat {
// 只写了有参构造,没有无参构造
public Cat(String name) {
this.name = name;
}
String name;
}
// 错误:没有无参构造,无法这样创建对象
Cat cat = new Cat();
正确写法:
class Cat {
// 手动添加无参构造
public Cat() {
}
// 有参构造
public Cat(String name) {
this.name = name;
}
String name;
}
// 正确:现在可以用无参构造创建对象
Cat cat = new Cat();
原因分析:一旦手动写了构造方法,Java 就不再自动生成默认无参构造,需要手动添加。
⚠️ 坑点 3:在 static 方法中使用 this
错误写法:
class Cat {
String name;
// 错误:static 方法中不能使用 this
public static void staticMethod() {
System.out.println(this.name);
}
}
正确写法:
class Cat {
static String name;
// 正确:static 方法使用 static 变量
public static void staticMethod() {
System.out.println(name);
}
}
原因分析:static 方法属于类,不属于对象,没有「当前对象」,所以不能使用 this