问题一:java的构造函数能否被继承?

笔者初学java看的一本书说:“java的子类自然的继承其超类的“非private成员”。

通常java的构造函数被设置为public的(若你不写构造函数,java自动添加的无参空构造函数就是public的),因本文中的类都在同一个包中,因此使用无修饰的友好权限说明问题,对于private构造函数的意义,可参见这里

那么根据该书所述规则,非private的构造函数当然也应该被子类继承。

但实际上,子类不仅无法继承private成员,也无法继承构造函数。

下面用代码进行说明。

示例1.

系统自动添加的无参空构造函数:(若不写构造函数,java默认添加一个无参的空构造函数)

  1. class base{
  2. }
  3. class derived extends base{
  4. public static void main(String[] args){
  5. derived d=new derived();
  6. }
  7. }

示例2.

把父类中系统自动添加的无参空构造函数显式的写出来(为了有输出,加了println):

  1. class base{
  2. base(){
  3. System.out.println("base constructor");
  4. }
  5. }
  6. class derived extends base{
  7. public static void main(String[] args){
  8. derived d=new derived();
  9. }
  10. }

输出结果:base constructor, 代码通过编译。从示例1,2来看,好像子类可以继承超类的构造函数哦。

但实际情况是:java规则:子类创建对象的同时会先创造父类的对象,因此必须先调用父类的构造方法。示例2中derived没有重写构造方法,根据java规则,系统会默认的添加一个无参的构造方法,且该方法第一句是super()。显式的写出来是:

  1. derived(){
  2. super();
  3. }

那为什么子类可以不写呢,因为:如果父类"只"有无参构造方法,且不打算重写子类的构造方法,为节省代码量,子类构造方法可以不写,系统默认调用父类无参构造方法super()。

可能还是有人觉得这些示例的说服力不够强,依然认为构造方法是可以继承的,没关系,看完本文,特别是示例4配合最后带★的文字,即可充分说明问题。

再来看看有参构造方法:

示例3.

如果将超类的构造方法改为有参构造方法,代码见下,则eclipse会报"Implicit super constructor xxx is undefined for default constructor. Must define an explicit constructor"

说明对于超类的有参构造方法,子类是无法继承的。

  1. class base{
  2. base(int x){
  3. System.out.println("base constructor,i="+x);
  4. }
  5. }
  6. class derived extends base{
  7. public static void main(String[] args){
  8. derived d=new derived();
  9. }
  10. }

对于有参的构造函数,子类中必须定义自己的构造方法。

(需要注意参数匹配,将该参数通过第一句的super(ParamList)传给父类的构造方法,若是多层继承,则需要逐级传递参数至最顶层的有参构造方法)

  1. class base{
  2. base(int x){
  3. System.out.println("base constructor,i="+x);
  4. }
  5. }
  6. class derived extends base{
  7. derived(int x){
  8. super(x);  //这里使用了super(param),调用了超类的构造方法。
  9. System.out.println("derived constructor,i="+x);
  10. }
  11. public static void main(String[] args){
  12. derived d=new derived(8);
  13. }
  14. }

输出结果:

base constructor,i=8

derived constructor,i=8

问题二:子类的构造函数可否不使用super(ParamList)调用超类的构造方法?

上例中使用了super调用了超类的构造方法。同样是那本书中说:“子类的构造方法中必须使用super调用超类的构造方法,且super必须是子类构造方法的第一句。”

那我不用super行不行呢?原话给人的感觉好像是java的语法规定一样。

其实可以不用显式的写出super,但前提是“超类中有多个构造方法,且有一个是显式写出的无参的构造方法”。

示例4.

超类拥有多个构造方法,其中一个是显式的无参的构造方法。

  1. class base {
  2. base() {                                          //warning_su
  3. System.out.println("base constructor.");  //warning_su
  4. }                                                 //warning_su
  5. base(int x) {
  6. System.out.println("base constructor,i=" + x);
  7. }
  8. }
  9. class derived extends base {
  10. derived() {                                        //warning_de
  11. System.out.println("derived constructor"); //warning_de
  12. }                                                  //warning_de
  13. derived(int x) {
  14. //super(x);                                //super被注释掉了!
  15. System.out.println("derived constructor,i=" + x);
  16. }
  17. public static void main(String[] args) {
  18. derived d= new derived();                       //warning_cr
  19. derived t = new derived(8);
  20. }
  21. }

输出结果:

base constructor.

derived constructor

base constructor.     <---------注意这里没有i=8哦。

derived constructor,i=8

此时,子类有参构造方法中没有使用super(x)调用超类的构造方法也通过编译了,但是不使用super(ParamList),new derived(8)调用的是超类的无参构造方法base()!

为什么要强调必须是“显式写出”的无参构造方法,您可以试试把带有warnning字样的代码注释掉(warning_su,warning_de,waring_cr3处),同时也注释掉super(x)。

因为此时超类和子类有构造方法(有参的那个),系统不会自动给超类添加无参的空构造函数,会造成子类找不到超类的无参构造方法super()来使用,同样会报"Implicit super constructor xxx is undefined for default constructor. Must define an explicit constructor"。

其实也说明了一个道理,即使我们不写super(),系统会自动的添加一句super(),此例中super()并不存在所以报错了。

当然,子类不调用超类的有参构造函数super(ParamList)的情况相对较少,所以那本书干脆说必须在第一句写上super(ParamList)。

★另外,如果单独注释掉子类中的无参构造函数derived()(不注释warning_su和warning_de),eclipse会说:"The constructor derived() is undefined"。

也证明了即使是无参构造函数,也是无法继承的。仅仅当超类中只有一个无参构造函数且不打算重写子类构造函数时,为节省工作量,子类构造函数可以不写,java在使用子类的构造函数时,自动添加一句super()来运行。

java构造函数是否可继承,以及子类构造函数可否不使用super调用超类构造函数的更多相关文章

  1. java学习之路--继承(子类构造器)

    子类的构造器不能访问父类的私有域,所以必须用的父类的构造器来对这部分的私有域进行初始化,我们可以通过super实现对父类的构造器的调用,使用super调用父类构造器的语句,必须放在子类构造器的第一句. ...

  2. JAVA的覆盖、继承和多态的详细解说.this和super的用法

    1. 继承: (1)子类的构造方法一定会调用父类的构造方法. (2)任何子类构造方法第一行肯定是this();或者super();两个择一. this();调用本类的其它构造方法.(传递相应参数调用相 ...

  3. 继承内部类时使用外部类对象.super()调用内部类的构造方法

    问题简介   今天在看<Java编程思想>的时候,看到了一个很特殊的语法,懵逼了半天--一个派生类继承自一个内部类,想要创建这个派生类的对象,首先得创建其父类的对象,也就是这个内部类,而调 ...

  4. Java学习笔记之继承

    一.继承的基础 在Java术语中,被继承的类叫超类(superclass)或者父类,继承超类的类叫子类(subclass). 举例说明: class Box { public double width ...

  5. c++继承构造子类调用父类构造函数的问题及关于容器指针的问题及当容器里储存指针时,记得要手动释放

    看下面的一个问题: class Person { private: string name; public: Person(const string& s=""){ nam ...

  6. 子类A继承父类B, A a = new A(); 则父类B构造函数、父类B静态代码块、父类B非静态代码块、子类A构造函数、子类A静态代码块、子类A非静态代码块 执行的先后顺序是

    按照先后顺序: 1,静态先于非静态代码库执行(静态代码块随着类的加载而加载,初始化只执行一次) 2,父类先于子类 3,非静态代码块优于构造函数执行 所以执行顺序如下: 父类B静态代码块->子类A ...

  7. 继承:继承后子类构造函数具有隐式super,所以子类中所以的构造函数默认会访问父类中的空参数的构造函数

    class Test { Test(){ System.out.println("Test"); } Test(String name){ System.out.println(& ...

  8. Java:【面向对象:类的定义,静态变量,成员变量,构造函数,封装与私有,this】

    本文内容: 什么是面对对象 类的定义与对象实例化 成员变量 成员变量的有效范围 成员变量的赋值 静态变量.方法与实例变量.方法 构造函数 封装与私有 this关键字 注:函数和方法是一样东西.[由于我 ...

  9. 23.C++- 继承的多种方式、显示调用父类构造函数、父子之间的同名函数、virtual虚函数

     上章链接: 22.C++- 继承与组合,protected访问级别 继承方式 继承方式位于定义子类的”:”后面,比如: class Line : public Object //继承方式是publi ...

随机推荐

  1. 教你上传代码到码云(与github一样)

    以下所有操作都在命令行进行 1 git 配置 git config --global user.name “用户名” git config --global user.email “邮箱”2 生成公钥 ...

  2. Libpacp 深度剖析

    Libpacp 深度剖析 1. Libpacp 的工作原理 ​ Libpcap的工作原理可以描述为,当一个数据包到达网卡时,通过网络分接口(即旁路机制)将数据包发给BPF过滤器,匹配通过的数据包可以被 ...

  3. Mac Hadoop2.6(CDH5.9.2)伪分布式集群安装

    操作系统: MAC OS X 一.准备 1. JDK 1.8 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-dow ...

  4. 解决mysql安装报错:无法启动此程序,因为计算机丢失MSVCP120.dll

    问题一: 因为装的是新系统,所以遇到mysql启动报错:无法启动此程序,因为计算机丢失MSVCP120.dll 后来参考这篇文章https://blog.csdn.net/huacode/articl ...

  5. uva-1636-概率

    https://vjudge.net/problem/UVA-1636 给出一个左轮手枪的弹夹串,第一枪是空的,问是继续打还是转一转再打下一枪还为空的概率大.继续打为空的概率就是 '00'的个数比上' ...

  6. 让FireFox支持window.event属性

    场景描述: 在用户行为采集的过程中,需要侦听window下的event对象,根据事件类型做相应的过滤处理,但在firefox下window.event是未定义的: 问题分析: 要想获取event属性共 ...

  7. 09_Git patch(补丁)操作

    Git打补丁,补丁操作一般在多人开发时才会用到,单人本地开发一般用不到,没必要.   应用场景举例: 我把我的更改打成一个补丁发给你,你来合并到你的代码中 或者,在家里电脑开发提交后,打一个补丁,拿到 ...

  8. Python基础学习----拆包

    拆包,多用在多值参数种. 1.多值参数. 有时候,在函数的参数转递时,不单只传输单个字符的参数,比如有元组和字典的参数,这时候我们就使用多值参数. *args 代表元组的多值参数 *kwargs 代表 ...

  9. MySQL 5.7忘记密码

    关闭正在运行的 MySQL : 1 [root@www.woai.it ~]# service mysql stop 运行 1 [root@www.woai.it ~]# mysqld_safe -- ...

  10. Visio2010建立ER图并直接导出为SQL语句

    Visio2010建立ER图并直接导出为SQL语句 2013年08月20日 ⁄ 综合 ⁄ 共 2581字 ⁄ 字号 小 中 大 ⁄ 评论关闭 建立数据库时我们需要考虑数据之间的关系,为了理清数据之间的 ...