由于Java对象构造非常重要,所以Java提供了多种编写构造器的机制。
1.重载
如果多个方法有相同的名字、不同的参数,便产生了重载。编译器必须挑选出具体执行哪个方法,它通过用各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出相应的方法。例如在下面的示例程序中,在创建第一位员工对象时执行第一个Empoyee构造器,在创建第二位员工对象时执行第二个Empoyee构造器,在创建第三位员工对象时执行第三个Empoyee构造器。
2.默认域初始化
如果在构造器中没有显式地给域赋值,那么就会被自动地赋为默认值:数值为0、布尔值为false、对象引用为null。如果不明确地对域进行初始化,就会影响程序代码的可读性。
3.无参数的构造器
对象由无参数构造函数创建时,其状态会设置为适当的默认值。如示例代码中,第三种重构方法Empoyee()就是无参数的构造函数。如果在编写一个类时没有编写构造函数,那么系统就会提供一个无参数构造器,这个构造器将所有的实例域设置为默认值。
4.显示域初始化
在执行构造器之前,先执行赋值操作。当一个类的所有构造器都希望把相同的值赋予某个特定的实例域是,这种方式特别有用。初始值不一定是常量值,可以调用方法对域进行初始化。如示例程序中的private String name = ""; // 实例域初始化,就是在每一个重载构造器初始化的时候都将name设置为""。
5.参数名
在参数命名上有两种方法。
通常是这种方法,但是只有阅读代码才能够了解参数n和参数s的含义。
1 public Employee(String n, double s) 2 { 3 name = n; 4 salary = s; 5 }
于是第一种常用方法是这种,在每个参数前面加上一个前缀“a”。
public Employee(String aName, double aSalary) { name = aName; salary = aSalary; }
第二种方法是为了让参数变量用相同的名字将实例域屏蔽起来。但是,如果将参数命名为salary,则salary将引用这个参数,而不是实例域。因此,可以采用this.salary的形式来访问实例域。之前的知识中介绍过,this指示隐式参数,也就是所构造的对象。
public Employee(String name , double salary ) { this.name = name ; this.salary = salary ; }
6.调用另一个构造器
如示例程序所示,当调用new Employee(60000)时,Employee(double)构造器将调用Employee(String, double)构造器。采用这种方式可以对公共构造器代码部分只编写一次即可。
7.初始化块
如果无论使用哪个构造器构造对象,域都在对象初始化块中被初始化时可以使用对象初始化块。先运行初始化块,再运行构造器主题部分。示例中的id域即为对象初始化块。
如果对类的静态域进行初始化的代码比较复杂,那么可以使用静态的初始化块。也就是将代码放在一个块中,并标记关键字static。示例中的nextId即为静态代码块初始化。
下面先给一段程序来说明构造器的多种特性应用。
1 package BigJunOba.bjtu.ConstructorTest; 2 3 import java.util.*; 4 5 public class ConstructorTest 6 { 7 public static void main(String[] args) 8 { 9 Employee[] staff = new Employee[3]; 10 11 staff[0] = new Employee("Harry", 40000); 12 staff[1] = new Employee(60000); 13 staff[2] = new Employee(); 14 15 for (Employee e : staff) 16 System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary=" 17 + e.getSalary()); 18 } 19 } 20 21 class Employee 22 { 23 private static int nextId; 24 25 private int id; 26 private String name = ""; // 实例域初始化 27 private double salary; 28 29 // 静态初始化块 30 static 31 { 32 Random generator = new Random(); 33 // 设置nextId为0到9999的随机数 34 nextId = generator.nextInt(10000); 35 } 36 37 // 对象初始化块 38 { 39 id = nextId; 40 nextId++; 41 } 42 43 // 重载构造器第一种Employee(String, double) 44 public Employee(String n, double s) 45 { 46 name = n; 47 salary = s; 48 } 49 50 // 重载构造器第二种Employee(double) 51 public Employee(double s) 52 { 53 // 用this调用另一个构造器,即调用Employee(String, double)构造器 54 this("Employee #" + nextId, s); 55 } 56 57 // 重载构造器第三种,即默认构造器Employee() 58 // 也是无参数构造器,其状态会设置为适当的默认值 59 public Employee() 60 { 61 // name在实例域初始化中被设置为"" 62 // salary没有被显示设置,因此初始化为默认值0 63 // id在对象初始化块中被设置为nextId 64 } 65 66 public String getName() 67 { 68 return name; 69 } 70 71 public double getSalary() 72 { 73 return salary; 74 } 75 76 public int getId() 77 { 78 return id; 79 } 80 }
输出结果:
name=Harry,id=6611,salary=40000.0 name=Employee #6612,id=6612,salary=60000.0 name=,id=6613,salary=0.0