默认域初始化
如果在构造器中没有显式地给域赋予初值,如下这样:
private String name;
private double salary;
//默认域初始化
public User() {
}
private String name;
private double salary;
//默认域初始化
public User() {
}
那么就会自动地赋为默认值:数值为0,布尔值为false,对象为null,但是我们一般不建议这么做,这样会大大的增加了阅读程序的难度,比如说上面的程序中,name被初始化为null,当我们调用一个新建User对象的 getName()方法,就会抛出一个空指针异常。所以,我们应该在初始化域的时候尽量不要采用默认值,而是赋予一些有意义的初始值。
无参构造
很多类都包含一个无参数的构造函数,对象由无参构造函数创建的时候,它的状态会被设置成适当的默认值,比如:
private String name;
private double salary;
//无参构造,初始化值
public User() {
name = "";
salary = 0;
}
private String name;
private double salary;
//无参构造,初始化值
public User() {
name = "";
salary = 0;
}
如果在编写一个类的时候忘记写构造器,不用担心,系统会提供一个无参的构造器,这个构造器将所有的实例域都设置为默认值,但是需要注意一点,如果类中提供了至少一个构造器,但是却没有提供无参构造,则在构造对象的时候没有提供参数就会视为不合法。 也就是说,仅仅当类没有提供任何构造器的时候,系统才会提供一个无参的构造器,如果在编写类的时候,给出了一个构造器,如果想要使用 newClassName()来构造对象,就必须提供一个默认的构造器(即不带参数的构造器)。
显式域初始化
当一个类的所有构造器都希望把相同的值赋予某个特定的实例域时,我们可以在类定义中,直接将一个值赋给这个特定的域:
class User {
private String name = "";
}
class User {
private String name = "";
}
当然,初始域也不一定非要是常量值,也可以调用方法对域进行初始化,比如我们使用方法来初始化User类的id,达到自动赋值的效果:
class User {
private static int nextId;
private int id = assignId();
private static int assignId() {
int r = nextId;
nextId++;
return r;
}
}
class User {
private static int nextId;
private int id = assignId();
private static int assignId() {
int r = nextId;
nextId++;
return r;
}
}
参数名
一般来说,我们在使用有参数的构造函数时,通常会用到this关键字用来区分实例域和参数名:
public User(String name, double salary) {
this.name = name;
this.salary = salary;
}
public User(String name, double salary) {
this.name = name;
this.salary = salary;
}
调用另一个构造器
如果构造器的第一个语句形如this(...),这个构造器将调用同一个类的另一个构造器,比如:
public User(double s) {
this("User #" + nextId, s)
nextId++;
}
public User(double s) {
this("User #" + nextId, s)
nextId++;
}
比如我们调用new User(3000)时候,User(double) 构造器将调用User(String, double)构造器。
采用着这种方式使用this关键字很有用,这样对公共的构造器代码部分只编写一次即可。
初始化块
在一个类的声明中,可以包含多个代码块。只要构造类的对象,这些块就会被执行。比如:
class User {
private static int nextId;
private int id;
private String name;
private double salary;
{
id = nextId;
nextId++;
}
public User(String name, double salary) {
this.name = name;
this.salary = salary;
}
public User() {
this.name = "";
this.salary = 0
}
}
class User {
private static int nextId;
private int id;
private String name;
private double salary;
{
id = nextId;
nextId++;
}
public User(String name, double salary) {
this.name = name;
this.salary = salary;
}
public User() {
this.name = "";
this.salary = 0
}
}
在这个实例中,无论使用哪个构造器构造对象,id域都在对象初始化块中被初始化,首先运行初始化块,然后才运行构造器的主体部分。
总结
上面我们一共说了三种构造器,下面时调用构造器的具体处理步骤
所有数据域被初始化为默认值(0,false或null)
按照在类声明中出现的次序,依次执行所有域初始化语句和初始化块
如果构造器第一行调用了第二个构造器,则执行第二个构造器主体
执行构造器主体。