Java对象创建与构造函数深度解析
立即解锁
发布时间: 2025-08-18 01:34:25 阅读量: 2 订阅数: 7 


Head First Java: Fun and Engaging Learning Experience
### Java 对象创建与构造函数深度解析
#### 一、实例变量的存储位置
在 Java 中,局部变量存储在栈上,那实例变量存储在哪里呢?当我们使用 `new CellPhone()` 语句时,Java 会在堆上为 `CellPhone` 对象分配空间。这个空间大小要足够容纳该对象的所有实例变量,也就是说,实例变量存储在堆上,位于它们所属的对象内部。
如果实例变量是基本数据类型,Java 会根据基本数据类型的大小为实例变量分配空间。例如,`int` 类型需要 32 位,`long` 类型需要 64 位。Java 并不关心基本变量内部的值,无论 `int` 变量的值是 32000000 还是 32,其占用的位大小都是 32 位。
如果实例变量是对象类型呢?假设 `CellPhone` 类中有一个 `Antenna` 类型的引用变量,即 `CellPhone HAS - A Antenna`。当新对象的实例变量是对象引用而不是基本数据类型时,真正的问题是:该对象是否需要为它所引用的所有对象分配空间?答案是否定的。无论如何,Java 都必须为实例变量的值分配空间。但要记住,引用变量的值并不是整个对象,而只是指向对象的“遥控器”。所以,如果 `CellPhone` 类中有一个声明为非基本类型 `Antenna` 的实例变量,Java 只会在 `CellPhone` 对象内部为 `Antenna` 的引用变量(即“遥控器”)分配空间,而不会为 `Antenna` 对象本身分配空间。
那么,`Antenna` 对象何时会在堆上获得空间呢?这取决于实例变量的声明。如果只声明了实例变量但没有为其分配对象,那么只会为引用变量(“遥控器”)创建空间。示例代码如下:
```java
private Antenna ant;
```
只有当引用变量被分配了一个新的 `Antenna` 对象时,才会在堆上创建实际的 `Antenna` 对象。示例代码如下:
```java
private Antenna ant = new Antenna();
```
以下是不同情况的总结表格:
| 情况 | 代码示例 | 说明 |
| ---- | ---- | ---- |
| 两个基本实例变量的对象 | 无(概念说明) | 变量的空间位于对象内部 |
| 一个未初始化的非基本实例变量的对象 |
```java
public class CellPhone {
private Antenna ant;
}
```
| 只有引用变量,无实际 `Antenna` 对象 |
| 一个已初始化的非基本实例变量的对象 |
```java
public class CellPhone {
private Antenna ant = new Antenna();
}
```
| 有引用变量且有实际 `Antenna` 对象 |
#### 二、对象创建的奥秘
现在我们知道了变量和对象的存储位置,接下来深入探讨对象创建的神秘世界。对象声明和赋值通常有三个步骤:声明引用变量、创建对象和将对象赋值给引用。
在这三个步骤中,第二步,也就是新对象“诞生”的这一步,一直是个大谜团。当我们看到 `new Duck()` 时,我们是在调用一个名为 `Duck()` 的方法吗?其实不是,我们调用的是 `Duck` 类的构造函数。
构造函数看起来和方法很相似,但它不是方法。构造函数包含了在使用 `new` 关键字时运行的代码,也就是在实例化对象时运行的代码。调用构造函数的唯一方式是使用 `new` 关键字后跟类名,JVM 会找到该类并调用其中的构造函数。
每个类都有构造函数,即使我们没有自己编写,编译器也会为我们生成一个默认的构造函数。编译器生成的默认构造函数如下:
```java
public Duck() {
}
```
构造函数与方法的不同之处在于,构造函数必须与类名相同,并且不能有返回类型。构造函数的关键特性是,它会在对象被赋值给引用之前运行。这意味着我们有机会在对象被使用之前对其进行一些准备工作。例如,在 `Duck` 类的构造函数中,我们可以为对象的实例变量赋值:
```java
public Duck() {
size = 34;
}
```
#### 三、构造函数的实际应用场景
在某些情况下,构造函数非常有用。以下是一些在 `Car` 类构造函数中可能有用的操作:
1. **递增计数器**:用于跟踪该类类型的对象创建数量。
2. **分配运行时特定状态**:分配关于当前正在发生的事情的数据。
3. **为对象的重要实例变量赋值**:确保对象在使用前具有必要的初始值。
4. **获取并保存创建新对象的对象的引用**:方便在新对象中访问创建它的对象。
5. **将对象添加到 `ArrayList` 中**:便于对对象进行管理和操作。
6. **创建 `HAS - A` 对象**:为对象创建关联的其他对象。
#### 四、使用构造函数初始化对象状态
大多数人使用构造函数来初始化对象的状态,即创建并为对象的实例变量赋值。但如果 `Duck` 类的开发者不知道 `Duck` 对象应该有多大,而希望使用 `Duck` 类的程序员来决定特定 `Duck` 对象的大小,该怎么办呢?我们可以在类中添加一个 `setSize()` 方法,但这样会使 `Duck` 对象在创建后暂时没有大小,并且需要调用者编写两条语句:一条用于创建 `Duck` 对象,另一条用于调用 `setSize()` 方法。
更好的做法是使用带参数的构造函数。例如:
```java
public class Duck {
int size;
public Duck(int duckSize) {
```
0
0
复制全文
相关推荐









