JAVA的每个类都必须至少有一个构造器(Constructor)。构造器是创建一个类的实例时需要调用的一个特殊的方法。利用构造器,可以产生一个类的实例,并且提供了一个地方用来定义创建类的实例时需要执行的初始化代码。它可以有访问修饰符、方法名称(和类名相同)、参数列表、方法体,但不能有返回类型声明。如果在程序中没有定义任何构造器,则编译器将会默认自动加上一个不带任何参数的构造器,这个构造器没有方法体。如果在程序中定义了构造器,则编译器将不再提供默认构造器,如果这时候再去使用默认构造器创建对象,将会编译出错。一个类里可以写多个构造器(构造器重载),需要使用哪个就调哪个。方法重载的要求:方法名相同,参数列表必须不同,返回值可以不同,权限可以不同,可以相互调用。比如下面这个程序,将正确执行。
class Dog {
private int weight;
private char sex;
public Dog(){
System.out.println ("默认构造器");
}
Dog(int weight){ //缺省权限
this.weight = weight;
System.out.println (this.weight);
}
private Dog(char sex){
Dog d = new Dog(2); //构造器中调用重载的构造器
this.sex = sex;
System.out.println (this.sex);
}
public static void main(String[] args) {
Dog d1 = new Dog();
Dog d2 = new Dog(20);
Dog d3 = new Dog('f');
} }
打印:
默认构造器
20
2
f
在继承关系中,子类在创建对象时,子类构造器将会先调用父类的构造器。如果子类的构造器中没有显示地调用父类构造器,也没有在构造器中调用重载的其它构造器,则系统将会默认调用父类中无参数的构造器。此时,如果父类中没有无参构造器,则编译出错。另外,如果父类的构造器的访问权限设置为私有,那么它的子类在构造过程当中,调用不到它,编译也会出错。
super关键字可以用于引用父类的成员,如属性、方法或者是构造器。super指代父类的实例。需要注意的是super的调用必须放在构造器中的第一句,而且super所调用的属性、方法、构造器的访问权限必须是可以让子类访问的权限。super主要用于在子类中定义了和父类中同名的属性,或进行了方法的覆盖,而又要在子类中访问父类中的同名属性或覆盖前的方法的时候。
方法重写(覆盖)的要求:和父类相同的方法名、参数、返回值,不能比父类更严格的权限。
当我们给一个重载构造器的时候,可能在一个构造器中的一段代码和另一个构造器完全一样,就可以在这个构造器中使用this直接调用另一个构造器,这样可以避免编写相同的代码。如果类中有多个其他构造器定义,系统将自动根据this()中的参数个数和参数类型来找出类中相匹配的构造器。需要注意的是,一个构造器中最多只能调用一次其他的构造器,并且对其他构造器的调用动作必须在构造器的起始处,否则编译出错,另外不能在构造器以外的地方以这种方式调用构造器。
自由块,又称游离块、初始化块。一般用静态自由块初始化静态变量。如果不new一个实例化对象,游离块也不执行。
下面我们通过一个详细的例子,深刻理解继承关系中的构造器、super关键字、this调用构造器、自由块的用法。
public class Person {
public String name;
public int age;
public String sex;
public Person(){
System.out.println ("构造器Person()被调用");
sex = "Male";
System.out.println
("name="+name+",age="+age+",sex="+sex);
}
public Person(String name){
this();//调用构造器Person()
System.out.println("构造器Person(String theName)被调用");
this.name = name;
System.out.println
("name="+name+",age="+age+",sex="+sex);
}
public Person(String name,int age){
this(name);//调用构造器Person(String name)
System.out.println("构造器Person(String name,int
age)被调用");
}
//初始化块
{
name = "Tony Blair";
sex = "Female";
System.out.println
("Person初始化块执行后:name="+name+",age="+age+",sex="+sex);
}
public String showName(){
return name;
}
}
public class Teacher extends Person {
private String department;
int schoolAge = 80;
public Teacher(){
System.out.println ("构造器Teacher()被调用");
}
public Teacher(String name){
//调用父类中的构造器Person(String name)
super(name);
System.out.println ("构造器Teacher()被调用");
}
public Teacher(int theSchoolAge){
schoolAge = theSchoolAge;
}
public Teacher(String dept,int theSchoolAge){
this(theSchoolAge);//调用本类重载的构造器Teacher(int
theSchoolAge)
department = dept;
} //方法覆盖
public String showName(){
System.out.println("department="+department+",schoolAge="+schoolAge);
return super.showName()+"老师";
}
//初始化块
{
department = "教务部";
System.out.println ("Teacher
初始化块执行后:name="+name+",age="+age+",sex="+sex+",schoolAge="+schoolAge);
}
}
public class TestInit {
public static void main(String[] args) {
System.out.println
("--------------------------------------------");
Teacher t1 = new Teacher();
System.out.println
("--------------------------------------------");
Teacher t2 = new Teacher("Tom");
System.out.println
("--------------------------------------------");
Teacher t3 = new Teacher("财务部",20);
System.out.println (t3.showName());
} }
打印输出:
--------------------------------------------
Person初始化块执行后:name=Tony Blair,age=0,sex=Female
构造器Person()被调用
name=Tony Blair,age=0,sex=Male
Teacher 初始化块执行后:name=Tony Blair,age=0,sex=Male,schoolAge=80
构造器Teacher()被调用
--------------------------------------------
Person初始化块执行后:name=Tony Blair,age=0,sex=Female
构造器Person()被调用
name=Tony Blair,age=0,sex=Male
构造器Person(String theName)被调用
name=Tom,age=0,sex=Male
Teacher 初始化块执行后:name=Tom,age=0,sex=Male,schoolAge=80
构造器Teacher()被调用
--------------------------------------------
Person初始化块执行后:name=Tony Blair,age=0,sex=Female
构造器Person()被调用
name=Tony Blair,age=0,sex=Male
Teacher 初始化块执行后:name=Tony Blair,age=0,sex=Male,schoolAge=80
department=财务部,schoolAge=20
Tony Blair老师
总结:
对象的初始化操作将递归如下的步骤来进行:
1、设置实例变量的值为缺省的初始值,比如int为0,引用类型为null等等。
2、调用类的构造器(但是还没有执行构造方法体),绑定构造器参数。
3、如果构造器中有this()调用,则先根据this()调用的参数调用相应的重载构造器。
4、如果构造器中有super()调用,根据super()中的参数调用父类中的相应构造器。如果没有这调用父类无参构造器。
5、调用父类中的初始化块初始化父类的属性,然后调用父类构造器。
6、返回子类,使用初始化程序和初始化块初始化成员。
7、执行子类构造器方法体中的其他语句。