Java对象构造与包机制详解
立即解锁
发布时间: 2025-08-18 00:07:20 阅读量: 1 订阅数: 11 

### Java对象构造与包机制详解
#### 1. 方法示例
首先看两个方法,`tripleSalary` 和 `swap`,以及 `Employee` 类的定义:
```java
public static void tripleSalary(Employee x) // works
{
x.raiseSalary(200);
System.out.println("End of method: salary=" + x.getSalary());
}
public static void swap(Employee x, Employee y)
{
Employee temp = x;
x = y;
y = temp;
System.out.println("End of method: x=" + x.getName());
System.out.println("End of method: y=" + y.getName());
}
class Employee // simplified Employee class
{
private String name;
private double salary;
public Employee(String n, double s)
{
name = n;
salary = s;
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
```
这里 `tripleSalary` 方法用于将员工的工资提高 200%,`swap` 方法尝试交换两个员工对象的引用。
#### 2. 对象构造机制
##### 2.1 重载(Overloading)
有些类拥有多个构造函数,这种能力称为重载。例如 `StringBuilder` 类:
```java
StringBuilder messages = new StringBuilder();
StringBuilder todoList = new StringBuilder("To do:\n");
```
重载发生在多个方法具有相同名称但不同参数的情况下。编译器通过匹配方法头中的参数类型与具体方法调用中使用的值的类型来选择正确的方法。如果编译器无法匹配参数,会发生编译时错误。
Java 允许重载任何方法,要完整描述一个方法,需要指定其名称和参数类型,这称为方法的签名。例如 `String` 类的 `indexOf` 方法有以下签名:
- `indexOf(int)`
- `indexOf(int, int)`
- `indexOf(String)`
- `indexOf(String, int)`
返回类型不是方法签名的一部分,不能有两个名称和参数类型相同但返回类型不同的方法。
##### 2.2 默认字段初始化(Default Field Initialization)
如果在构造函数中没有显式设置字段,它将自动设置为默认值:数字为 0,布尔值为 false,对象引用为 null。依赖默认值被认为是不好的编程习惯,因为这会使代码难以理解。
例如,对于 `Employee` 类,如果在构造函数中没有指定如何初始化某些字段,`salary` 字段将初始化为 0,`name` 和 `hireDay` 字段将初始化为 null。如果调用 `getName` 或 `getHireDay` 方法,可能会得到意外的 null 引用。
##### 2.3 无参数构造函数(The Constructor with No Arguments)
许多类包含无参数构造函数,用于创建具有适当默认状态的对象。例如 `Employee` 类的无参数构造函数:
```java
public Employee()
{
name = "";
salary = 0;
hireDay = LocalDate.now();
}
```
如果一个类没有任何构造函数,Java 会提供一个无参数构造函数,将所有实例字段设置为默认值。但如果类提供了至少一个构造函数但没有无参数构造函数,不提供参数创建对象是非法的。
需要注意的是,只有当类没有其他构造函数时,才会自动获得无参数构造函数。如果编写了自己的构造函数并希望用户能够通过 `new ClassName()` 创建实例,就必须提供无参数构造函数。
##### 2.4 显式字段初始化(Explicit Field Initialization)
通过重载类的构造函数,可以有多种方式设置类的实例字段的初始状态。确保无论调用哪个构造函数,每个实例字段都被设置为有意义的值是个好主意。
可以在类定义中直接为任何字段赋值,例如:
```java
class Employee
{
private String name = "";
...
}
```
这种赋值在构造函数执行之前进行,当类的所有构造函数都需要将某个特定实例字段设置为相同值时,这种语法特别有用。
初始化值不一定是常量值,也可以是方法调用。例如,为 `Employee` 类的 `id` 字段初始化:
```java
class Employee
{
private static int nextId;
private int id = assignId();
...
private static int assignId()
{
int r = nextId;
nextId++;
return r;
}
...
}
```
在 C++ 中,不能直接初始化类的实例字段,所有字段必须在构造函数中设置。但 C++ 有特殊的初始化列表语法。
##### 2.5 参数名称(Parameter Names)
编写简单构造函数时,为参数命名可能会有些麻烦。常见的做法有:
- 使用单字母参数名称,如 `public Employee(String n, double s)`,但缺点是需要阅读代码才能理解参数的含义。
- 为每个参数添加 “a” 前缀,如 `public Employee(String aName, double aSalary)`,这样读者可以立即理解参数的含义。
- 利用参数变量会遮蔽同名实例字段的特性,使用 `this` 关键字访问实例字段,例如:
```java
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
```
在 C++ 中,通常会在实例字段前添加下划线或固定字母,而 Java 程序员通常不这样做。
##### 2.6 调用另一个构造函数(Calling Another Constructor)
`this` 关键字除了表示方法的隐式参数外,还有另一个含义。如果构造函数的第一行具有 `this(...)` 的形式,那么该构造函数将调用同一个类的另一个构造函数。例如:
```java
public Employee(double s)
{
// calls Employee(String, double)
this("Employee #" + nextId, s);
nextId++;
}
```
当调用 `new Employee(60000)` 时,`Employee(double)` 构造函数会调用 `Employee(String, double)` 构造函数。使用 `this` 关键字可以避免重复编写通用的构造代码。
在 C++ 中,一个构造函数不能调用另一个构造函数,如果要提取通用的初始化代码,必须编写一个单
0
0
复制全文
相关推荐









