首先, 构造方法本身会有一个隐式的无参构造(默认):
1不写构造方法, 类中的第一行代码事实上有一个默认的无参构造(系统会隐式为你写好)
- public class Student {
- private String name;
- // public Student() {} 隐式地 "写" 在这里, 你看不见
- // Strudent 类中虽然没有写构造方法, 但相当于有上面的无参构造
- // 只不过是隐式的, 你看不见
- }
2只写带参构造方法, 相当于只有该带参构造方法(隐式的无参构造会被屏蔽无视掉, 视为无效)
- public class Student {
- private String name;
- public Student(String name) {
- this.name=name;
- }
- // 此时原来 Strudent 类中的隐式的无参构造方法被屏蔽了, 无效了
- // 类中只有带参构造
- }
3若想同时拥有无参和带参构造, 必须显式地写出无参和带参构造方法
- public class Student {
- private String name;
- public Student() {}
- // 显式地将无参构造写出来
- public Student(String name) {
- this.name=name;
- }
- // 若想 Strudent 类中拥有无参构造方法, 必须显式地写出来
- }
进一步结合继承, 就需要考虑到子父类:
4在子类的构造方法 (无论是无参和有参) 中, 方法中的第一行代码事实上都隐式地包含了父类的无参构造方法
即: super()
- public class Stu extends Student {
- private String name;
- public Stu() {
- // super();
- // 在子类的无参构造中, super()是隐式的 "写" 在这里的
- }
- public Stu(String name) {
- // super();
- this.name=name;
- // 在子类的带参构造, 上面的 super()同样也是隐式的 "写" 在这里的
- }
- }
这就是为什么, 调用子类的构造方法时, 都会先调用父类的无参构造方法了, 因为默认的 super()存在.
5同理, 类似与上面的2, 此时若写一个有参构造, super(xx)会把隐式的 super()屏蔽掉
- public class Stu extends Student {
- private String name;
- public Stu(String name) {
- // super(); 原来隐式写在这里的 super()被屏蔽了, 无效了
- super(name);
- // 在子类的带参构造, 由于的 super(name)的存在, super()无效了
- // 此时子类的带参构造中, 只有 super(name)
- }
- }
这就是为什么当父类没有无参构造 (即只有带参构造 -- 对应情况2) 时, 子类的构造方法编译无法通过. 这是因为子类的构造函数 (带参或无参) 将调用父类的无参构造函数. 由于编译器试图向子类中的 2 个构造函数中插入 super() , 但父类的默认构造函数未定义, 因此编译器会报告错误消息.
要解决这个问题, 只需要
1)添加一个无参构造函数给父类 -- 显式地在父类中添加无参构造
2)删除父类中自定义的有参构造函数 -- 等价于恢复了默认的无参构造
3)将 Super(XXX) 添加到子类构造函数 -- 通过5的原来来屏蔽默认的 super()
一些关于子父类有参无参的组合情况 (其实就是排列组合) 练习, 有兴趣的可以自己验证一下, 如下(图片来源 https://blog.csdn.net/asd991543753/article/details/89284108):
来源: http://www.bubuko.com/infodetail-3299619.html