10.
【知识点】
1. 具有继承关系的类在实例化过程中构造方法的链式调用关系
类实例化是通过调用自己的构造方法完成的。子类实例化时会先自动创建超类的实例对象,这个道理类似于要有孩子就得先有父母的存在。
从类的继承关系来看,创建子类实例需要在继承树上一直追溯到最基本的根类,然后,从根类开始按继承关系边下溯边逐层调用各个类的构造方法创建继承链上所有类的实例。
由于类的多态性,一个类可能会有多个不同构造方法,从子类向根类追溯过程中,子类需要明确知道调用超类的哪个构造方法才能实例化超类,也就是说,子类的构造方法中可以显式使用super关键词调用超类中对应的构造方法,超类中被调用的构造方法也必须存在,否则就会编译失败。
如果子类的构造方法没有显式调用超类中任何构造方法,系统就默认调用超类的无参构造方法。如果超类中没有显式定义任何构造方法,系统会自动隐式提供默认的无参构造方法,但是,如果超类中已经定义了任何构造方法,系统就不会再提供默认构造方法,对于这种情况,就必须在超类中显式定义无参构造方法,否则会造成编译失败。
2. 默认无参构造方法(Default No-Argument Constructor)
Java语言规定,在定义一个类时可以不提供任何构造方法,编译器会自动提供默认无参构造方法,但是,如果没有构造方法的是子类,编译器为它提供的默认无参构造方法就会自动去调用超类的无参构造方法,这时,只要超类已经定义了任何有参构造方法,即使没有显式定义无参构造方法,系统也不会再提供默认无参构造方法,编译就会失败。
当然,如果自定义的类没有超类,那就意味着它的超类是系统提供Objec,幸运的是,Object类提供了无参构造方法,不必担心编译失败了。
【例题】
What is the result?
public class Person {
Stringname = "No name";
publicPerson(String nm) { name = nm; }
}
public class Employee extends Person {
String empID= "0000";
publicEmployee(String id) { empID = id; }
}
public class EmployeeTest {
publicstatic void main(String[] args){
Employee e= new Employee("4321");
System.out.println(e.empID);
}
}
A. 4321
B. 0000
C. An exception is thrown at runtime.
D. Compilation fails because of an error in line 18.
【Answer】 D
【例题辨析】
Employee类提供有参构造方法:
public Employee(String id) { empID = id; }
在这个构造方法中,没有调用超类Person的任何构造方法,默认将调用超类Person的无参构造方法,而超类Person中定义了有参构造方法并没有定义无参构造方法,由于Person已经有了构造方法,系统就不会再为Person提供默认无参构造方法,这样就因Person类没有无参构造方法造成编译失败。
解决方案可以任选下面一种:
(1)在Employee类的有参构造方法中显式调用超类中已经定义的有参构造方法,如:
publicEmployee(String id) {
super(id);// 调用超类的有参构造方法
empID = id; }
}
(2)在Person类中添加显式定义的无参构造方法:
publicPerson() { }