面向对象编程
类与对象
重要
一个完整的类:
- 核心组成部分
- 属性(实例变量-每个对象独立拥有的属性、静态变量-类级别共享)
- 构造方法:初始化对象状态
- 实例方法:定义对象的行为,可以访问实例变量和静态变量
- 静态方法:定义类级别的行为,只能访问静态变量
- Getter/Setter:控制字段的访问权限(封装性)
- 访问修饰符(封装):控制类成员的可见性
- 面向对象特性
- 继承(extends):复用代码,建立类层次关系
- 多态(方法重写、父类引用子类对象)
- 抽象类与接口
- 内部类:逻辑分组,增强封装性
- 扩展内容
- 枚举类型
- 注解
- 泛型
- 单例模式
- 类设计原则
- 单一职责原则:一个类只负责一个功能领域
- 开闭原则:对扩展开放,对修改封闭(通过继承/组合扩展)
- 高内聚低耦合:类内部高度聚合,类之间依赖最小化
public class Person {
// 实例变量(对象特有属性)
private String name;
private int age;
// 静态变量(类级别共享)
public static String species = "Human";
// 构造方法(初始化对象)
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 实例方法
public void introduce() {
System.out.println("Hi, I'm " + name + ", " + age + " years old.");
}
// 静态方法
public static void displaySpecies() {
System.out.println("Species: " + species);
}
// Getter & Setter(可选)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 测试入口
public static void main(String[] args) {
// 创建对象(触发堆内存分配)
Person alice = new Person("Alice", 30);
alice.introduce(); // 输出: Hi, I'm Alice, 30 years old.
// 访问静态变量
System.out.println(Person.species); // 输出: Human
Person.displaySpecies(); // 输出: Species: Human
// 修改静态变量(影响所有实例)
Person.species = "Homo sapiens";
System.out.println(Person.species); // 输出: Homo sapiens
}
}
类和对象的内存分配机制(对象创建的流程分析)
- Java内存的结构分析
- 栈区(Stack):存储 局部变量 、方法调用栈帧
- 堆区(Heap):存储所有对象实例和数组
- 方法区:类结构、静态变量、常量池、JIT代码
提示
此处加配图:对象创建的流程分析 内存分配 方法调用过程等
在Java中,对象创建和内存分配涉及多个内存区域的协作,以创建一个Person
类对象为例,分析内存结构的关键步骤如下:
类加载 方法区:
- 加载类的字节码文件(
.class
文件) - 存储静态变量
species
,初始化值为"Human"
- 存储方法代码(构造方法、
introduce()
、displaySpecies()
等方法的字节码) - 存储常量池(如字符串常量
"Hi, I'm "
)
- 加载类的字节码文件(
对象实例化(堆内存)
- 分配对象内存空间(包含对象头、实例变量name和age)
- name字段指向堆中独立的String对象(存储 "Alice" 的字符数组)
- age字段直接存储原始值30
栈内存与引用关联
- main 方法的栈帧中存储局部变量 alice(保存堆中 Person 对象的内存地址)
- 方法调用时(如 alice.introduce()),栈中压入新的栈帧(存储方法参数、局部变量等)
方法调用 栈帧管理方法调用过程中的参数传递和局部变量
静态变量访问 直接读写方法区中的静态变量species(无需对象实例)
成员方法的传参机制
- 基本数据类型:传递的是值(值拷贝),形参的改变不影响实参
- 引用数据类型:传递的是地址(传递的也是值,但是值是地址),可以通过形参影响实参
方法重载(Overload)
- 方法名:必须相同
- 形参列表:形参类型或个数或顺序,至少有一样不同,参数名无要求
- 返回类型:无要求
访问修饰符
访问级别 | 访问控制修饰符类 | 同类 | 同包 | 子类 | 不同包 |
---|---|---|---|---|---|
公开 | public | ✔ | ✔ | ✔ | ✔ |
受保护 | protected | ✔ | ✔ | ✔ | ❌ |
默认 | 无修饰符 | ✔ | ✔ | ❌ | ❌ |
私有 | private | ✔ | ❌ | ❌ | ❌ |
面向对象编程
封装、继承、多态
封装
封装:把抽象出的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作【方法】,才能对数据进行操作。
封装的步骤:
- 将属性私有化
private
- 提供公共的
public
set
方法,用于对属性判断并赋值 - 提供公共的
public
get
方法,用于获取属性的值
继承
继承:当多个类之间存在相同的属性和方法时,可以从这些类中抽象出符类,在父类中定义这些相同的属性和方法,子类通过extends
来声明继承父类即可拥有父类定义的属性和方法,从而建立类之间的层级关系,实现代码复用和逻辑扩展。
提示
添加继承的本质分析
继承的内存布局
super和this关键字的对比
区别点 | this | super |
---|---|---|
访问 属性 | 访问本类中的属性,如果本类没有此属性,则从父类继续查找 | 从父类开始查找属性 |
调用 方法 | 访问本类中的方法,如果本类没有此方法,则从父类继续查找 | 从父类开始查找方法 |
调用 构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在子类构造器的首行 |
特殊 | 表示当前对象 | 子类中访问父类对象 |
方法重写(Override)
方法重写:子类重写父类的方法,子类中的某个方法和父类中某个方法的名称、返回类型、形参列表都一样。
多态
多态的前提是,两个对象(类)存在继承关系
重要
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型是可以变化的
- 编译类型看定义时
=
号的左边,运行类型看=
号的右边
多态的向上转型
- 父类引用指向子类对象
- 语法:
父类类型 引用名=new 子类类型();
- 特点:编译类型看左边,运行类型看右边。
- 可以调用父类中的所有成员(需遵守访问权限)
- 不能调用子类中特有成员
- 最终运行效果看子类的具体实现
多态的向下转型
- 语法:
子类类型引用名=(子类类型)父类引用
- 只能强转父类的引用,不能强转父类的对象
- 要求父类的引用必须指向的是当前目标类型的对象
- 当向下转型后,可以调用子类类型中所有的成员
Java的动态绑定机制
重要
- 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
- 当调用对象属性的时候,没有动态绑定机制,哪里声明,哪里使用