Java的每个类都必须有自己的构造方法,若是没有显式的用代码写出来,则系统会默认一个空的构造方法。在继承中,子类同样要有自己的构造方法,但必须遵循如下规则:
- 子类的构造过程中必须调用其父类的构造方法;
- 子类可以在自己的构造方法中使用super(argument_list)调用其父类的构造方法;
- 子类可以在自己的构造方法中使用this(argument_list)调用自己的其它构造方法;
- 如果调用super(argument_list),this(argument_list),必须写在子类构造方法的第一行;
- 如果子类构造方法中没有显式地调用父类构造方法,则系统默认调用基类无参数构造方法;
- 如果子类构造方法中既没有显式地调用父类构造方法,而父类中又没有无参构造方法,则编译出错;
- 并不是每个子类的构造方法都必须显式地调用父类构造方法,可以通过this(argument_list)调用自己的有调用父类构造方法的其它构造方法。
我们先来看看一段未调用父类构造方法的错误的代码:
// 未调用父类构造方法的错误代码
class Person{
Person(String n){
System.out.println("Person: String n");
}
}
class Student extends Person {
Student(String n){
System.out.println("Student: String n");
}
}
public class SuperClassTestErr1 {
public static void main(String[] args){
Person p1 = new Person("p1");
Student s1 = new Student("s1");
}
}
编译,系统报错:
在子类构造方法中调用父类构造方法即可修正:
//修正错误的代码
class Person{
Person(String n){
System.out.println("Person: String n");
}
}
class Student extends Person {
Student(String n){
super(n); //调用父类构造方法
System.out.println("Student: String n");
}
}
public class SuperClassTestErr1 {
public static void main(String[] args){
Person p1 = new Person("p1");
Student s1 = new Student("s1");
}
}
在学习的过程中,网上一般都只说前面几个规则,说得最多的是第5,6两个规则,一个简单的理解就是:子类构造函数一定要调用父类构造函数,否则会编译出错。但在学习过程中,出现了疑惑,见如下代码:
代码 一(通过其它构造函数调用父类构造函数):
public class TestSuperSub {
public static void main(String[] args){
Person p1 = new Person("P1");
Person p2 = new Person("P2","ShangHai");
Student s1 = new Student("s1","school1");
Student s2 = new Student("s2","Shanghai","school2");
System.out.println(p1.info());
System.out.println(p2.info());
System.out.println(s1.info());
System.out.println(s2.info());
}
}
class Person {
private String name;
private String location;
Person(String name) {
this.name = name;
location = "beijing";
}
Person(String name, String location) {
this.name = name;
this.location = location;
}
public String info(){
return "name: "+name+ " location: "+location;
}
}
class Student extends Person {
private String school;
Student(String name, String school) {
this(name,"beijing",school);
}
Student(String n, String l, String School){
super(n,l);
this.school = school;
}
public String info(){
return super.info()+" school: "+school;
}
}
该代码能编译成功,也能正确运行,但其中Student的构造方法并未显式地调用父类构造方法,为何没错呢:
Student(String name, String school) {
this(name,"beijing",school);
}
再看看另一段代码:
代码 二(通过其它构造函数调用父类构造函数)
public class SuperClassTest {
public static void main(String args[]){
B aB = new B("3");
}
}
class A{
private String a1;
// A(){
// System.out.println("A");
// }
A(String s) {
a1 = s;
System.out.println(a1);
}
A(String s1, String s2){
System.out.println(s1+s2);
}
}
class B extends A{
private String b1;
private String b2;
private String b3;
B(String b1){
super(b1);
System.out.println(b1);
}
// B(int i) {
// super("i");
// System.out.println("B");
// System.out.println(i);
// }
B(String b1,String b2){
//super(b1,b2);
this(b1);
b2 = b2;
}
B(String b1, String b2, String b3){
this(b1,b2);
b3 = b3;
}
}
这段代码中的子类B共有三个构造函数,后两个函数也没有调用父类构造函数,并且父类也没有定义空构造函数。但这段代码同样通过编译。
其原因是:
B(String b1, String b2, String b3)第1行调用了子类本身构造函数this(b1,b2)
B(String b1, String b2)第1行调用了子类本身构造函数this(b1)
而B(String b1)第1行调用了父类构造函数super(b1)
由上可知:
并不是每个子类的构造方法都必须显式地调用父类构造方法,可以通过this(argument_list)调用自己的有调用父类构造方法的其它构造方法。