构造器定义
构造器是用来初始化类实例。在对象编程语言中,一般在定义了一个类型之后,为了能使用它,必须把这个类型具体化,也就是指定为一个具体的对象。而构造函数就是从定义出发,建立与定义相对应的对象。用计算机语言来说,光有定义是不能使用,必须通过构造函数来分配内存空间给可使用的对象。
构造器的声明语法
<作用域> <类名> (<参数列表>){
<方法体>
}
构造器的使用规则
- 构造器的名称始终与其类名相同
- 一个类可以有多个构造器
- 构造器可以有0、1个或多个参数
- 构造器始终使用new关键字进行调用
- 构造器没有返回值
构造方法与成员方法的区别
- 修饰符不同
构造方法只能使用public、private、protected访问修饰符,而不能使用static、final、synchronized、abstract等非访问修饰符。这是因为构造方法用于初始化一个实例对象,所以static修饰是没有任何意义的;多个线程不会同时创建内存地址相同的同一个对象,所以synchronized修饰没有意义;构造方法不能被子类继承,所以final和abstract修饰没有意义。 - 返回值不同
构造方法没有返回值。 - 构造方法名与类名相同。
缺省构造器
- 每个类至少有一个构造器
- 如果你没有手工编写一个构造器,则系统在编译时自动添加一个缺省构造器
public class A {
public static void main(String[] args) {
A a = new A();//调用系统默认的无参构造器
}
}
- 一旦自己定义了自己的构造函数java就会收回自己的默认构造函数,因此建议自己要书写无参构造函数。
public class A {
public A(String name){
System.out.println(name);
}
public static void main(String[] args) {
//A a = new A();//报错,因为没有相应的无参构造函数的定义
A a2 = new A("a2");//输出结果为:a2
}
}
构造器不能被继承
- 子类继承父类所有的成员方法和成员变量
- 但子类不继承父类的构造器。
调用其他构造器
- 调用父类构造器用super()方法
使用super可以调用父类的构造器
public class A {
public A(){
System.out.println("A--无参构造器");
}
public A(String name){
System.out.println("A--有参构造器:"+name);
}
}
public class B extends A{
public B(){
super();
System.out.println("B--无参构造器");
}
public B(String name){
super(name);
System.out.println("B--有参构造器:"+name);
}
public static void main(String[] args) {
B b1 = new B();
System.out.println("--------------");
B b2 = new B("b2");
}
}
//输出结果为:
/*
A--无参构造器
B--无参构造器
--------------
A--有参构造器:b2
B--有参构造器:b2
*/
使用super也可以在成员方法中调用父类的成员方法
public class A {
public void method(){
System.out.println("method:A");
}
}
public class B extends A{
public void method(){
System.out.println("method:B");
super.method();
}
public static void main(String[] args) {
B b1 = new B();
b1.method();
}
}
//运行结果为:
//A--无参构造器
//B--无参构造器
- 调用当前类构造器用this()方法
this在构造器中可以调用其他的构造器,但必须在第一行且只能调用一次。
public class A {
public A(){
System.out.println("无参构造器");
}
public A(String name){
this();
System.out.println("有参构造器:"+name);
}
public static void main(String[] args) {
A a2 = new A("a2");//有参构造器
}
}
//运行结果为:
//无参构造器
//有参构造器:a2
另外,this关键字也代表当前的实例对象,因此this关键字不能用于static方法中。
public void setName(String name) {
this.name = name;
}
- 子类默认调用父类的无参构造器,如果父类自己定义了有参构造器而没有定义无参构造器,那么就会报错。但这时如果子类显示的调用父类的有参构造器,就不会报错。
public class A {
public A(String name){
System.out.println("A--有参构造器:"+name);
}
}
public class B extends A{
public B(String name){
super(name);
System.out.println("B--有参构造器:"+name);
}
public static void main(String[] args) {
B b2 = new B("b2");
}
}
//输出结果为:
//A--有参构造器:b2
//B--有参构造器:b2
从上例也可以看出先初始化父类的构造器,再初始化子类的构造器。
初始化顺序问题
初始化顺序:
1. 静态成员首先被初始化且只初始化一次。
2. 父类构造器被初始化。
3. 实例变量被初始化。
4. 本类构造方法被初始化。
由下述代码可得上述结论
public class A {
public A(){
System.out.println("A--无参构造器");
}
public A(String name){
System.out.println("A--有参构造器:"+name);
}
}
public class B extends A{
A a2 = new A("a2");
static A a3 = new A();
public B(String name){
super(name);
System.out.println("B--有参构造器:"+name);
}
public static void main(String[] args) {
B b1 = new B("b1");
B b2 = new B("b2");
}
}
//运行结果为:
/**
A--无参构造器
A--有参构造器:b1
A--有参构造器:a2
B--有参构造器:b1
A--有参构造器:b2
A--有参构造器:a2
B--有参构造器:b2
*/