8. Java 面向对象核心笔记
·
一、面向对象核心概念
1.1 基本思想
将程序拆解为对象的集合,每个对象是"数据(属性)+ 行为(方法)"的封装体。程序运行的本质是对象之间互相发送消息(方法调用)。
1.2 三大特性
| 特性 | 说明 | 类比 |
|---|---|---|
| 封装 | 隐藏内部实现细节,仅暴露必要接口 | 手机充电口对外,内部电路隐藏 |
| 继承 | 子类复用父类的属性和方法,减少重复代码 | 大学生类继承学生类 |
| 多态 | 同一方法,不同对象表现不同行为 | 动物类 叫():猫→"喵"、狗→"汪" |
二、类与对象
2.1 概念对应
| 概念 | Java 表述 |
|---|---|
| 类属性 | static 修饰的成员变量(静态变量) |
| 实例属性 | 无 static 的成员变量 |
| 实例方法 | 无 static 的成员方法(隐含 this) |
| 类方法 | static 修饰的方法 |
| 初始化方法 | 构造方法(与类同名,无返回值) |
2.2 完整代码示例:学生类
public class Student {
// 1. 类属性(静态变量):所有对象共享
public static String species = "人类";
public static String school = "XX中学";
// 2. 实例属性(成员变量):每个对象独有
private String stuId;
private String name;
private int age;
private String grade; // 默认值 null
// 3. 构造方法:创建对象时初始化
public Student(String stuId, String name, int age) {
this.stuId = stuId;
this.name = name;
this.age = age;
}
// 4. 实例方法:操作实例属性
public void attendClass(String course) {
System.out.printf("%s(学号%s)正在上%s课%n", this.name, this.stuId, course);
}
// 5. 类方法(静态方法):操作类属性
public static void showSchool() {
System.out.println("当前学校:" + Student.school);
}
// 6. 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) { this.age = age; }
public String getGrade() { return grade; }
public void setGrade(String grade) { this.grade = grade; }
// 测试入口
public static void main(String[] args) {
Student stu1 = new Student("2026001", "张三", 16);
stu1.setGrade("高一1班");
stu1.attendClass("数学"); // 张三(学号2026001)正在上数学课
Student stu2 = new Student("2026002", "李四", 17);
stu2.setGrade("高一2班");
stu2.attendClass("英语"); // 李四(学号2026002)正在上英语课
System.out.println(Student.species); // 人类
Student.showSchool(); // 当前学校:XX中学
}
}
2.3 static 与非 static
| 修饰符 | 级别 | 所属 | 访问方式 |
|---|---|---|---|
static |
类级别 | 整个类,所有对象共享 | 类名 / 对象名(推荐类名) |
无 static |
对象级别 | 每个对象独有 | 必须通过对象访问 |
三、封装
3.1 核心定义
封装是面向对象三大特性之一,核心原则:隐藏内部细节,暴露安全接口。通过访问控制禁止外部直接操作内部数据,仅通过指定方法交互。
3.2 实现步骤
步骤一:私有化成员变量
public class Student {
private String name;
private int age;
}
步骤二:提供公共 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 && age <= 120) {
this.age = age;
} else {
throw new IllegalArgumentException("年龄必须在0-120之间");
}
}
步骤三:有参构造复用 setter
public Student(String name, int age) {
this.name = name;
this.setAge(age); // 复用校验逻辑
}
3.3 访问权限修饰符
| 修饰符 | 本类 | 同包类 | 子类(不同包) | 其他类 |
|---|---|---|---|---|
private |
可访问 | 不可 | 不可 | 不可 |
| 默认(不写) | 可访问 | 可访问 | 不可 | 不可 |
protected |
可访问 | 可访问 | 可访问 | 不可 |
public |
可访问 | 可访问 | 可访问 | 可访问 |
封装中:成员变量用 private,getter/setter 用 public。
3.4 注意事项
- getter/setter 命名规范:
get+ 变量名首字母大写(布尔类型可用is),set+ 变量名首字母大写。 - 构造方法中调用 setter 以复用数据校验逻辑。
- 不过度封装:仅暴露必要的接口,不需要每个成员都提供 getter/setter。
四、Java 内存分区与对象内存分析
4.1 内存分区
| 内存区域 | 存储内容 | 生命周期 |
|---|---|---|
| 栈内存 | 局部变量、方法调用栈 | 方法执行完毕出栈释放 |
| 堆内存 | new 创建的对象(含成员变量)、JDK 7+ 字符串常量池 |
GC 自动回收 |
4.2 单个对象调用方法 — 内存流程
Person p = new Person();
p.name = "张三";
p.age = 20;
p.show();
main进栈,定义p。new Person():堆中开辟空间,name=null、age=0,生成地址(如0x123)。p(栈)存储地址0x123,指向堆中对象。p.name = "张三":通过地址修改堆中name;同理age = 20。p.show():show进栈,this指向0x123,读取name和age输出。show出栈 →main出栈。
4.3 多个对象调用方法
Person p1 = new Person();
p1.name = "王五";
Person p2 = new Person();
p2.name = "赵六";
p1.show();
p2.show();
p1指向堆空间 1(0x789),p2指向堆空间 2(0xabc)。- 两次
show()调用时,this分别指向各自堆对象,输出各自数据。
4.4 多个引用指向同一对象
Person p3 = p1; // p3 和 p1 指向堆中同一对象
修改 p3 的成员变量会影响 p1,因为指向同一堆地址。
五、基本数据类型与引用数据类型
5.1 基本数据类型(8 种)
| 类型 | 关键字 | 占用内存 | 取值范围 | 默认值 |
|---|---|---|---|---|
| 字节型 | byte |
1 字节 | -128 ~ 127 | 0 |
| 短整型 | short |
2 字节 | -32768 ~ 32767 | 0 |
| 整型 | int |
4 字节 | 约 ±21 亿 | 0 |
| 长整型 | long |
8 字节 | -2^63 ~ 2^63-1 | 0L |
| 单精度浮点 | float |
4 字节 | 约 ±3.4×10^38 | 0.0f |
| 双精度浮点 | double |
8 字节 | 约 ±1.8×10^308 | 0.0d |
| 字符型 | char |
2 字节 | \u0000 ~ \uffff | '\u0000' |
| 布尔型 | boolean |
1 字节 | true / false | false |
- 直接存储值,存于栈内存(局部变量)。
- 赋值时为值传递:
int b = a;复制的是值,修改b不影响a。
5.2 引用数据类型
包含类(String、自定义类)、接口(List)、数组(int[])。变量存储的是堆对象地址。赋值时为引用传递:复制的是地址,指向同一堆对象。
5.3 值传递 vs 引用传递
// 基本类型:值传递,不影响原变量
public static void change(int num) { num = 20; }
int a = 10; change(a);
System.out.println(a); // 10
// 引用类型:引用传递,修改堆对象
public static void change(Person p) { p.name = "李四"; }
Person p1 = new Person(); p1.name = "张三"; change(p1);
System.out.println(p1.name); // 李四
5.4 String 的特殊性
String 是引用类型但不可变,赋值 / 传参时表现类似值传递:
public static void change(String str) { str = "world"; } // str 指向新对象
String s = "hello"; change(s);
System.out.println(s); // hello(原对象未变)
5.5 总结对比
| 对比项 | 基本数据类型 | 引用数据类型 |
|---|---|---|
| 存储内容 | 实际值 | 堆对象地址 |
| 存储位置 | 栈 | 栈(引用)+ 堆(对象) |
| 传递方式 | 值传递(副本) | 引用传递(地址) |
| 修改影响 | 不影响原变量 | 影响堆中对象(String 除外) |
六、this 关键字
6.1 核心作用
this 代表当前对象的引用(堆内存地址),由 JVM 自动传入每个非静态方法。
| 作用 | 说明 |
|---|---|
| 区分成员变量与局部变量 | this.name = name; |
| 调用当前对象的成员方法 | this.show(); |
| 调用当前类的构造方法 | this(参数),必须位于构造方法第一行 |
| 作为方法返回值 | return this; |
6.2 内存原理
public void setName(String name) {
this.name = name; // this 指向调用该方法的对象
}
Student s1 = new Student(); // 假设地址 0x123
s1.setName("张三"); // JVM 实际传递:setName(s1, "张三"),this = 0x123
方法进栈时 JVM 自动传入调用对象的地址作为 this,通过 this 定位堆中对象并操作其成员。
6.3 注意事项
- 仅非静态方法中有
this,静态方法属于类,不依赖对象。 this不能为null,对象创建后地址非null。this(参数)调用构造方法时,必须写在构造方法的第一行。
七、成员变量与局部变量
7.1 定义
| 类型 | 定义位置 | 所属 |
|---|---|---|
| 成员变量 | 类中、方法外 | 对象 / 类 |
| 局部变量 | 方法内、代码块中、方法参数 | 方法 / 代码块 |
7.2 五维度对比
| 对比维度 | 成员变量 | 局部变量 |
|---|---|---|
| 定义位置 | 类中、方法外 | 方法内 / 代码块 / 方法参数 |
| 作用域 | 整个类(随修饰符变化) | 所在的方法 / 代码块内部 |
| 默认值 | 有默认值 | 无默认值,须显式赋值后使用 |
| 存储位置 | 实例:堆内存;静态:方法区 | 栈内存(方法栈帧中) |
| 生命周期 | 实例:随对象创建 / 回收;静态:随类加载 / 卸载 | 随方法 / 代码块执行创建、结束销毁 |
7.3 同名变量优先级
方法内默认访问局部变量;访问成员变量需使用 this(实例成员)或类名(静态成员):
class Person {
String name = "成员变量";
public void test() {
String name = "局部变量";
System.out.println(name); // 局部变量
System.out.println(this.name); // 成员变量
}
}
八、总结
- 类是抽象模板,对象是具体实例,通过
new 类名(参数)创建。 static区分类级别和对象级别的属性和方法;属性私有化 + getter/setter 实现封装。- 对象存堆、引用存栈;多引用可指向同一对象。
- 基本类型值传递、引用类型地址传递(String 不可变特性例外)。
this由 JVM 自动传入,关联方法与调用对象,实现对当前对象成员的操作。- 成员变量作用域广、有默认值;局部变量作用域窄、须显式赋值。
更多推荐
所有评论(0)