Java Constructor 链与实例
构造函数链是指从另一个构造函数中调用一个与当前对象有关的构造函数的过程。
构造函数链的主要用途之一是在拥有多个构造函数时避免重复的代码(通过构造函数重载),并使代码更加可读。
Prerequisite - Constructors in Java
构造函数链可以通过两种方式进行:
- 在同一类中 :可以使用 this() 关键字对同一类中的构造函数进行连锁。
- 从基类: 通过使用 super() 关键字来调用基类中的构造函数。
构造函数链通过 继承 发生 。 一个子类构造函数的任务是首先调用超类的构造函数。这确保了子类对象的创建从超类的数据成员的初始化开始。继承链中可以有任何数量的类。每个构造函数都会向上调用链,直到到达顶端的类。
为什么我们需要构造函数链 ?
当我们想在一个构造函数中执行多个任务时,就会使用这个过程,而不是在一个构造函数中为每个任务创建代码,我们为每个任务创建一个单独的构造函数,并使其成为一个链,这使程序更易读。
在同一个类中使用this()关键字进行构造函数链 。
// Java program to illustrate Constructor Chaining
// within same class Using this() keyword
class Temp
{
// default constructor 1
// default constructor will call another constructor
// using this keyword from same class
Temp()
{
// calls constructor 2
this(5);
System.out.println("The Default constructor");
}
// parameterized constructor 2
Temp(int x)
{
// calls constructor 3
this(5, 15);
System.out.println(x);
}
// parameterized constructor 3
Temp(int x, int y)
{
System.out.println(x * y);
}
public static void main(String args[])
{
// invokes default constructor first
new Temp();
}
}
输出
75
5
The Default constructor
构造函数链的规则。
- this() 表达式应该始终是构造函数的第一行。
- 至少应该有一个没有this()关键字的构造函数(上例中的构造函数3)。
- 构造函数链可以以任何顺序实现。
如果我们改变构造函数的顺序会怎样?
没有,构造函数链可以以任何顺序实现
// Java program to illustrate Constructor Chaining
// within same class Using this() keyword
// and changing order of constructors
class Temp
{
// default constructor 1
Temp()
{
System.out.println("default");
}
// parameterized constructor 2
Temp(int x)
{
// invokes default constructor
this();
System.out.println(x);
}
// parameterized constructor 3
Temp(int x, int y)
{
// invokes parameterized constructor 2
this(5);
System.out.println(x * y);
}
public static void main(String args[])
{
// invokes parameterized constructor 3
new Temp(8, 10);
}
}
输出
default
5
80
注意:在例子1中,默认的构造函数在最后被调用,但在例子2中,默认的构造函数在第一个被调用。因此,构造函数链的顺序并不重要。
使用super()关键字与其他类进行构造函数链。
// Java program to illustrate Constructor Chaining to
// other class using super() keyword
class Base
{
String name;
// constructor 1
Base()
{
this("");
System.out.println("No-argument constructor of" +
" base class");
}
// constructor 2
Base(String name)
{
this.name = name;
System.out.println("Calling parameterized constructor"
+ " of base");
}
}
class Derived extends Base
{
// constructor 3
Derived()
{
System.out.println("No-argument constructor " +
"of derived");
}
// parameterized constructor 4
Derived(String name)
{
// invokes base class constructor 2
super(name);
System.out.println("Calling parameterized " +
"constructor of derived");
}
public static void main(String args[])
{
// calls parameterized constructor 4
Derived obj = new Derived("test");
// Calls No-argument constructor
// Derived obj = new Derived();
}
}
输出
Calling parameterized constructor of base
Calling parameterized constructor of derived
注意:与同一类中的构造函数链类似, super() 应该是构造函数的第一行,因为超类的构造函数会在子类的构造函数之前被调用。
替代方法:使用Init块 :
当我们希望每个构造函数都执行某些公共资源时,我们可以将代码放在 init块 中 。 Init块总是在任何构造函数之前执行,只要一个构造函数被用来创建一个新对象。
例子1:
class Temp
{
// block to be executed before any constructor.
{
System.out.println("init block");
}
// no-arg constructor
Temp()
{
System.out.println("default");
}
// constructor with one argument.
Temp(int x)
{
System.out.println(x);
}
public static void main(String[] args)
{
// Object creation by calling no-argument
// constructor.
new Temp();
// Object creation by calling parameterized
// constructor with one parameter.
new Temp(10);
}
}
输出:
init block
default
init block
10
注意:如果有一个以上的块,它们将按照它们在同一个类中定义的顺序执行。见例。
例子:
class Temp
{
// block to be executed first
{
System.out.println("init");
}
Temp()
{
System.out.println("default");
}
Temp(int x)
{
System.out.println(x);
}
// block to be executed after the first block
// which has been defined above.
{
System.out.println("second");
}
public static void main(String args[])
{
new Temp();
new Temp(10);
}
}
输出:
init
second
default
init
second
10