内存管理与对象模型
自动垃圾回收(GC)
Java通过JVM的垃圾回收机制自动管理内存,开发者无需手动释放对象。所有对象通过new在堆上创建,生命周期由GC决定。例如:
| |
引用类型对象模型
Java中所有非基本类型(如int、double)的对象变量存储的是堆上对象的引用(可视为安全的指针)。与C++不同,Java不允许在栈上直接创建对象实例:
| |
参数传递特性
Java的对象参数传递是引用的按值传递。这意味着方法内部对引用的修改不会影响外部变量,但可以通过引用修改对象的状态。
构造器(Constructor)与初始化
初始化方式
Java的成员变量初始化通常在构造器方法体内完成,或在声明时直接赋值:
| |
构造器调用规则
- 子类构造器必须在第一行显式调用父类构造器(
super(参数))。若未显式调用,编译器会自动插入super()(调用父类无参构造器)。若父类无无参构造器,子类必须显式调用。 - 构造器委托:通过
this(参数)调用同一类的其他构造器,必须是构造器的第一条语句:
| |
默认构造器
若未定义任何构造器,编译器会自动生成一个无参默认构造器(public)。一旦定义任意构造器,编译器不再提供默认构造器。
继承(Inheritance)与接口(Interface)
单继承与接口实现
Java采用单继承(一个类只能有一个直接父类),通过extends实现继承。为弥补多继承缺失,Java引入接口(interface),允许类实现多个接口(implements):
| |
继承的核心用途
- 代码复用:子类直接使用父类的属性和方法。
- 类型层次结构:构建从抽象到具体的分类体系(如
Dog is an Animal)。
接口的设计哲学
接口定义行为契约(“能做什么”),而非类型(“是什么”)。实现接口的类必须提供所有抽象方法的具体实现,从而实现多态和解耦。
接口冲突处理
当多个接口定义同名方法时,实现类需根据以下规则处理:
- 方法签名相同(参数、返回类型一致):实现类只需提供一次公共实现。无论通过哪个接口的引用来调用该方法,最终执行的都是子类中的单一实现。
- 方法签名不同(参数不同):实现类需分别实现每个方法。这属于方法重载(Overload)的范畴。
- 方法签名相同但返回类型不同:编译失败。Java不允许定义两个只有返回类型不同的同名方法。
示例场景
假设Game和Artwork接口均定义了play()方法,而Starfield类同时实现这两个接口:
| |
此时Starfield只需提供一次play()的实现,即可满足两个接口的契约。
多态(Polymorphism)与方法重写
默认虚函数机制
Java中所有非static、非private的方法默认是虚函数,支持运行时多态。子类通过@Override注解重写父类方法:
| |
方法重写 vs. 重载
- 重写(Override):子类重新定义父类方法(方法签名完全相同)。
- 重载(Overload):同一类中同名方法参数列表不同(参数个数、类型或顺序不同)。
访问控制与封装
四种访问修饰符
Java通过四类访问修饰符控制成员可见性,从宽松到严格依次为:public > protected > default(包私有) > private。
| 修饰符 | 同一类 | 同一包 | 子类(不同包) | 其他包 |
|---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | ❌ |
default | ✅ | ✅ | ❌ | ❌ |
private | ✅ | ❌ | ❌ | ❌ |
最佳实践
- 将字段设为
private,通过public的getter/setter控制访问。 - 接口和公共API使用
public,内部实现细节使用protected或default。
其他关键特性
泛型(Generics)
Java泛型通过类型擦除实现,运行时所有泛型信息会被擦除:
| |
总结
Java的类设计在继承、内存管理、多态等方面与传统OOP语言存在显著差异。理解其自动内存管理、引用模型、单继承+多接口机制,以及默认虚函数和访问控制策略,是掌握Java面向对象编程的核心。对于有工程经验的开发者,建议重点关注接口设计、多态实现和访问控制的实际应用场景。
